Getting Started with IOS 5 storyboards (2)

Source: Internet
Author: User
Template cells

Notice that when you join Tableviewcontroller, does Xcode issue a warning?

"Unsupported configuration:prototypetable cells must have reuse identifiers" when adding a Tableviewcontroller to the storyboard, Xcode A prototype cells cell (template cells) is used by default. But we didn't configure it, so we have this warning.

Template cells is a cool story board feature. It is far better than the original nib file. Previously, if you were customizing a table view cell, you would either add your own subviews to the cell object in your code, or create a new nib and load your own cell from the nib. But the advent of template cells simplifies all of this, and now you can design your own table view cells directly in the storyboard editor.

Tableviewcontroller comes with a blank template cell on it. Click on this cell and you can set its style to Subtitle in the Properties panel. This causes the cell to become a cell containing two labels. If you've ever created Tableviewcell yourself manually, you should know that this is the Uitableviewcellstylesubtitle style. With template cells, you can create a built-in style cell, or you can create a fully customizable cell (we'll mention it right away).

Change the Accessory property to Disclosure Indicator and then set the Reuse Identifier (multiplexing ID) to Playercell. This way, Xcode immediately removes the warning. All the templates cells are still normal UITableViewCell objects and will still have a multiplexing Id,xcode just prompt us not to forget to set it (at least let us notice this warning).

Run the program and nothing has changed. Don't be surprised, we haven't provided the data source, so no rows are displayed in the table view.

Add a new File to the project. Select the Uiviewcontrollersubclass template. Name the class Playersviewcontroller to make sure it inherits from Uitableviewcontroller. Do not select the "withxib ..." option because we have already designed a UI for this class in the story version. We don't need nib! anymore.

Go back to the story editor and select Tableviewcontroller. In the identity panel, set its Class to Playersviewcontroller. This step is important because it associates a scene in the story version with your own Viewcontroller subclass. Be sure to remember this step, otherwise you will be completely useless to create the class!

From now on, the Tableviewcontroller in the storyboard after running the program will become an instance of our Playersviewcontroller class.

Add a variable array property to the PlayersViewController.h file:

#import <UIKit/UIKit.h>  @interface playersviewcontroller:uitableviewcontroller  @property (nonatomic , strong) Nsmutablearray * players;  @end


This array stores the model data in the application, which is the player (player) object. Now create the player class. Create a new File, using the Objective-c class template. Named Player, Inherits NSObject.

Player.h file:

@interface player:nsobject  @property (nonatomic, copy) NSString * name; @property (nonatomic, copy) NSString * GA Me; @property (nonatomic, assign) int rating;  @end


PLAYER.M file

#import "Player.h"  @implementation Player  @synthesize name; @synthesize game; @synthesize rating;  @end


None of this is surprising. The player is a simple object with 3 attributes: The player's name, the game played by the player, and the level (1-5 stars).

We'll put an array in the appdelegate and put some player objects in the array to test. This array will be assigned to the players property of the Playerviewcontroller.

In APPDELEGATE.M, add an import statement for the Player class and the Playersviewcontroller class, and add an instance variable called players:

  #import "AppDelegate.h" #import "Player.h" #import "PlayersViewController.h"  @implementation appdelegate {    Nsmutablearray * PLAYERS;}  ......


To modify the Didfinishlaunchingwithoptions method:

-(BOOL) Application:( UIApplication *) Application Didfinishlaunchingwithoptions:(        Nsdictionary *) launchoptions {players = [Nsmutablearray arraywithcapacity:20];        Player * player = [[Player alloc] init];        Player.name = @ "Bill Evans";        Player.game = @ "Tic-Tac-Toe";        player.rating = 4;        [Players Addobject:player];        Player = [[Player alloc] init];        Player.name = @ "Oscar Peterson";        Player.game = @ "Spin the Bottle";        player.rating = 5;        [Players Addobject:player];        Player = [[Player alloc] init];        Player.name = @ "Dave Brubeck";        Player.game = @ "Texas Hold ' em Poker";        player.rating = 2;        [Players Addobject:player];             Uitabbarcontroller * Tabbarcontroller = (Uitabbarcontroller *) Self.window.rootViewController; Uinavigationcontroller * Navigationcontroller = [[Tabbarcontroller viewcontrollers] objectatindex:0 ] ;                 Playersviewcontroller * Playersviewcontroller = [[Navigationcontroller viewcontrollers] objectatindex:0];         Playersviewcontroller.players = players; return YES;}


First, some Player objects are created and added to the players array. And then:

Uitabbarcontroller * Tabbarcontroller = (Uitabbarcontroller *)    Self.window.rootViewController; Uinavigationcontroller * Navigationcontroller =     [[Tabbarcontroller viewcontrollers] objectatindex:0]; Playersviewcontroller * Playersviewcontroller =     [[Navigationcontroller viewcontrollers] objectatindex:0];p layer Sviewcontroller.players = players;


Yes, what is this? We want to assign the players array to the players property of Playersviewcontroller so that it can be used as the Tabeviewcontroller data source. But the application delegate doesn't know where Playersviewcontroller is, so we have to get it out of the storyboard. This is one of the things that bothers me about using the storyboard. If you are using IB, there will be a reference to the application delegate in Mainwindow.xib, and you can connect the top-level viewcontroller to the Iboutlet property of the application delegate. But now it's impossible to use the storyboard. The application delegate can no longer be referenced in the top-level Viewcontroller. This is a real misfortune, and we can only get references by way of code.

Uitabbarcontroller * Tabbarcontroller = (Uitabbarcontroller *)    Self.window.rootViewController;


We know that the initial view controller of the storyboard is a tabbarcontroller, so we can get a reference to it from the Rootviewcontroller of the Window object and make the type conversion.

Playersviewcontroller is located in the first tab of the Navigationcontroller container, so we first get the Uinavigationcontroller object:

Uinavigationcontroller * Navigationcontroller = [[Tabbarcontroller    viewcontrollers] objectatindex:0];



Then in Navigationcontroller's Rootviewcontroller, you can get Playersviewcontroller:

Playersviewcontroller * Playersviewcontroller =     [[Navigationcontroller viewcontrollers] objectatindex:0];



However, Uinavigationcontroller does not have a Rootviewcontroller property. So we have to retrieve it from the viewcontrollers array. (It has a Topviewcontroller property, but that is the view controller at the top of the viewcontrollers stack.) And what we want is a low-stack view controller. Although the top and bottom of the stack are actually one when the program starts, you can also use Topviewcontroller, but it's not so secure.

Now that we have the Player array, we can go back to creating our data source in Playersviewcontroller.

Open the PLAYERSVIEWCONTROLLER.M and modify the table view's data source method:

-(Nsinteger) Numberofsectionsintableview:( UITableView *) TableView {        return 1;}  -(Nsinteger) TableView:( UITableView *) TableView    numberofrowsinsection:( Nsinteger) Section {        return [self.players count];}


The important thing is the Cellforrowatindexpath method. The template code created by Xcode is this:

-(UITableViewCell *) TableView:( UITableView *) TableView    Cellforrowatindexpath:( Nsindexpath *) Indexpath {     static NSString * Cellidentifier = @ "Cell";       UITableViewCell * cell = [TableView               dequeuereusablecellwithidentifier:cellidentifier];     if (cell = = nil) {         cell = [[UITableViewCell alloc]                      initwithstyle:uitableviewcellstyledefault            reuseidenti Fier:cellidentifier];     }     Configure the cell     ... return cell;}


There is no doubt that you have written your own table View code in this place countless times. But it's different now. Modify the code to:

-(UITableViewCell *) TableView:( UITableView *) TableView Cellforrowatindexpath:( Nsindexpath *) Indexpath {        UITableViewCell * cell = [TableView                dequeuereusablecellwithidentifier: @ "Playercell " ] ;        Player * player = [self.players ObjectAtIndex:indexPath.row];                 Cell.textLabel.text = Player.name;    Cell.detailTextLabel.text = Player.game;     return cell;}


The code becomes simpler! In fact, you just need to get a new cell from here:

UITableViewCell * cell = [TableView    dequeuereusablecellwithidentifier: @ "Playercell"];



No longer need to reuse cells, it will automatically get a copy from the template cell for you to use! You only need to provide a duplicate ID (you've already set up the template cell in the story editor, in this case, "Playercell"). Remember to set this ID, otherwise the template cell will not take effect.

Since Playersviewcontroller does not know the player class, you also need to import the header file of the player class:

#import "Player.h"

Also to synthesize the players attribute:

@synthesize players;

Run the program as shown in:

Note: In this example, we only use a template cell, and if you need to display multiple cells, you can add more template cells. You can copy the existing template cell to the new cell, or you can increase the TableView Prototype Cells property value. Note that each template cell has its own reuse ID.

Using the Magic template cell just one line of code, this is a great thing!

Design a fully customizable template cell

For most apps, it's enough to use the standard cell style. But I want to add a picture to the right of the cell to show the player level (in the form of stars). UITableViewCell's standard style does not include the ability to put a ImageView in a cell, so I can only select a custom design.

Back to Mainstoryboard.storyboard, select template cell and set the Style property to Custom. The default label disappears.

First increase the cell's height to 55 pixels. Drag the handle at the bottom of it to change its height, or you can modify the Row height value in the size panel.

Drag two labels into the Cell, placing them roughly equal to where they were originally. Feel free to modify their fonts and colors. The high light color of the two labels is white. This will look better when the user clicks on the cell, because the cell's background is blue.

Drag a ImageView to the right end of the cell, close to the right arrow. Adjust it to a width of 81, height does not matter. Set its Mode to Center (below the view in the Properties panel) so that it will not be stretched when we put the picture in it.

I set the width of the two labels to 210, which does not obscure the ImageView. The final design is done this way:

Because it is a custom cell, we no longer use the cell's Textlabel and Detailtextlabel properties to display text. The properties of these two tags no longer exist in our cell.

We will retrieve the Label we want through tag.

For the Name tag, the tag is set to 100, and for the Game tag, the tag is set to 102. You can set the tag in the Properties panel.

Open PLAYERSVIEWCONTROLLER.M, and modify the Cellforrowatindexpath method to:

-(UITableViewCell *) TableView:( UITableView *) TableView    Cellforrowatindexpath:( Nsindexpath *) Indexpath {        UITableViewCell * cell = [TableView        dequeuereusablecellwithidentifier: @ "Playercell " ] ;        Player * player = [self.players ObjectAtIndex:indexPath.row];                 UILabel * Namelabel = (UILabel *) [cell viewwithtag:100];         namelabel.text= Player.name;        UILabel * Gamelabel = (UILabel *) [cell viewwithtag:101];        Gamelabel.text = Player.name;        Uiimageview * Ratingimageview = (Uiimageview *)        [cell viewwithtag:102];        Ratingimageview.image = [self imageForRating:player.rating];     return cell;}

Here's a new method called Imageforrating, which is implemented as follows:

-(UIImage *) imageforrating:(int) Rating {        switch (rating)        {case               1:return [UIImage imagenamed: @ " 1starsmall.png "];               Case 2:return [UIImage imagenamed: @ "2starssmall.png"];               Case 3:return [UIImage imagenamed: @ "3starssmall.png"];               Case 4:return [UIImage imagenamed: @ "4starssmall.png"];               Case 5:return [UIImage imagenamed: @ "5starssmall.png"];        }        return nil;}

Run the program again.

Aha, it looks a little out of the way. We have modified the height of the template cell, but TableView does not know. There are two ways to change the Row Height property of the table view, or to modify the Heightforrowatindexpath method. The former is much simpler, so I used the former.

Note: If you cannot determine the cell height beforehand, or if you have several cells of different heights, you should use Heightforrowatindexpath.

Return Mainstoryboard.storyboard, in the Size panel of TableView, set Row Height to 55

If you change the cell's height by dragging rather than typing directly, the TableView Row height property will automatically change.

Run the program again, this time it looks much better.

Subclass Template Cell

Our Table View looks great! But I don't like to use tag to access UILabel and other cell subview. Wouldn't it be better if these labels could connect to the Iboutlet property?

Add a new File to your project, using the Objective-c class template. The class name is Playercell and inherits from UITableViewCell.

Modify the PlayerCell.h to:

@interface Playercell:uitableviewcell  @property (nonatomic, strong) iboutlet UILabel * Namelabel; @property (Nonat Omic, Strong) iboutlet UILabel * Gamelabel; @property (nonatomic, strong) Iboutlet Uiimageview    * ratingimageview;
   @end

Modify the PLAYERCELL.M to:

#import "PlayerCell.h"  @implementation Playercell  @synthesize namelabel; @synthesize Gamelabel; @synthesize Ratingimageview;  @end

The content is not much, just add a few attributes, Namelabel, Gamelabel and Ratingimageview.

Back to Mainstoryboard.storyboard, select template cell and change its Class to "Playercell" in the Identity panel. So when you get a cell using the Dequeuereusablecellwithidentifier method, it actually returns a Playercell to you.

Notice that I took the name of the class and the reuse ID as the same--it's called playercell--, which is just because I like it. In fact, they have nothing to do with it, and you make them completely different.

Select, you can connect the label and ImageView to the Iboutlet. Select the label and drag a line from its connection panel to Tableviewcell, or drag it from Tableviewcell to the label with CTRL + left.

Important: You can establish a connection between the control and the Tableviewcell, not just between the control and the Viewcontroller! As you can see, when your data source uses Dequeuereusablecellwithidentifier to request a new cell from a Table View, TableView doesn't really give you the template cell, it just gives you a copy of the template cell (may also be an existing cell--in the case of multiplexing). This means that there are multiple Playercell instances at any time. If you connect a label on the cell to the Viewcontroller Iboutlet, then there will be more than one label trying to use the same iboutlet. That would be a problem. (Incidentally, if you have a Custom Button or other control on your cell, you can connect the template cell to the Viewcontroller action.)

Now, we've connected these properties. Our code can become more concise:

-(UITableViewCell *) TableView:( UITableView *) TableView Cellforrowatindexpath:( Nsindexpath *) Indexpath {        Playercell * cell = (Playercell *) [TableView               dequeuereusablecellwithidentifier: @ "P Layercell "];        Player * player = [self.players ObjectAtIndex:indexPath.row];        Cell.nameLabel.text = Player.name;        Cell.gameLabel.text = Player.game;    Cell.ratingImageView.image = [self                imageForRating:player.rating];     return cell;}

That's the same thing. We convert the result returned by Dequeuereusablecellwithidentifier to Playercell, and then use its properties to access the Label and Uiimageview. I really like using the template cell, which makes my tableview code look much neater.

Of course, you still need to import the Playercell class:

#import "PlayerCell.h"

Run the program exactly as before, but using our own Tableviewcell subclass in the table.

There are some design techniques. When designing your own Tableviewcell, you need to be aware of some places. First, you should set the label's highlighted Color (high light) so that the user feels better when they click on the table row.

Second, you should make sure that the added content automatically adapts to the change in cell size. For example, when you need a table row to be deleted or moved, the Cell size changes.

Add the following methods to PLAYERVIEWCONTROLLER.M:

-(void) TableView:( UITableView *) TableView Commiteditingstyle:( Uitableviewcelleditingstyle) Editingstyle Forrowatindexpath:( Nsindexpath *) Indexpath {        if (Editingstyle = = Uitableviewcelleditingstyledelete)       {               [self.players RemoveObjectAtIndex:indexPath.row];               [TableView deleterowsatindexpaths: [Nsarray Arraywithobject:indexpath]                withrowanimation: Uitableviewrowanimationfade];        }    }

After implementing this method, the "swipe to delete" function of the table is turned on. Run the program, swipe the gesture on a line, and see what happens.

The Delete button appears on the cell, but it also obscures the level picture. In fact, because the delete button occupies some cell space, and the cell size changes, ImageView does not change.

To resolve this problem, open Mainstoryboard.storyboard, select ImageView, modify the autosizing in the Size panel so that it is always on the right side of Superview:

The label's autosizing is set as follows, so when the cell size changes, the label's size changes as well:

After these adjustments, the Delete button appears to squeeze the star icon to the left:


You can also let the stars disappear when the Delete button appears, which is left to the reader to implement. The important thing is that you should be clear about these details when designing Tableviewcell.

What's next

In the second part of this tutorial, we included the following: Segues, static Tableviewcell, add player window, game Selection window, and sample code for this tutorial!


These are the contents of the iOS 5 Storyboard Primer (2) and more about topic.alibabacloud.com (www.php.cn)!

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.