Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Beginning iOS5 Development.pdf
Скачиваний:
7
Добавлен:
09.05.2015
Размер:
15.6 Mб
Скачать

CHAPTER 8: Introduction to Table Views

237

Creating a UITableViewCell Subclass

Up until this point, the standard table view cells we’ve been using have taken care of all the details of cell layout for us. Our controller code has been kept clear of the messy details about where to place labels and images, and has been able to just pass off the display values to the cell. This keeps presentation logic out of the controller, and that’s a really good design to stick to. For this project, we’re going to make a new cell subclass of our own that takes care of the details for the new layout, which will keep our controller as simple as possible.

Adding New Cells

Select the Cells folder in the project navigator, and press N to create a new file. In the assistant that pops up, choose Objective-C class from the Cocoa Touch section, and click Next. On the following screen, enter BIDNameAndColorCell as the name of the new class, select UITableViewCell in the Subclass of popup list, and click Next again. On the final screen, select the Cells folder that already contains your other source code, make sure Cells is chosen both in the Group and Target controls at the bottom, and click Create.

Select BIDNameAndColorCell.h, and add the following code:

#import <UIKit/UIKit.h>

@interface BIDNameAndColorCell : UITableViewCell

@property (copy, nonatomic) NSString *name; @property (copy, nonatomic) NSString *color;

@end

Here, we’ve defined two properties that our controller will use to pass values to each cell. Note that instead of declaring the NSString properties with strong semantics, we’re using copy. Doing so with NSString values is always a good idea, because there’s a risk that the string value passed in to a property setter may actually be an NSMutableString, which the sender can modify later on, leading to problems. Copying each string that’s passed in to a property gives us a stable, unchangeable snapshot of what the string contains at the moment the setter is called.

That’s all we need to expose in the header, so let’s move on to

BIDNameAndColorCell.m. Add the following code at the top of the file:

#import "BIDNameAndColorCell.h"

#define

kNameValueTag

1

#define

kColorValueTag

2

@implementation BIDNameAndColorCell

@synthesize name; @synthesize color;

.

.

.

www.it-ebooks.info

238

CHAPTER 8: Introduction to Table Views

Notice that we’ve defined two constants. We’re going to use these to assign tags to some of the subviews that we’ll be adding to the table view cell. We’ll add four subviews to the cell, and two of those need to be changed for every row. In order to do that, we need some mechanism that will allow us to retrieve the two fields from the cell when we go to update that cell with a particular row’s data. If we set unique tag values for each label that we’ll use again, we’ll be able to retrieve them from the table view cell and set their values. We also declared the name and color properties, which the controller will use to set the values that should appear in the cell.

Now, edit the existing initWithStyle:reuseIdentifier: method to create the views that we’ll need to display.

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

{

self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) {

// Initialization code

CGRect nameLabelRect = CGRectMake(0, 5, 70, 15);

UILabel *nameLabel = [[UILabel alloc] initWithFrame:nameLabelRect]; nameLabel.textAlignment = UITextAlignmentRight;

nameLabel.text = @"Name:";

nameLabel.font = [UIFont boldSystemFontOfSize:12]; [self.contentView addSubview: nameLabel];

CGRect colorLabelRect = CGRectMake(0, 26, 70, 15);

UILabel *colorLabel = [[UILabel alloc] initWithFrame:colorLabelRect]; colorLabel.textAlignment = UITextAlignmentRight;

colorLabel.text = @"Color:";

colorLabel.font = [UIFont boldSystemFontOfSize:12]; [self.contentView addSubview: colorLabel];

CGRect nameValueRect = CGRectMake(80, 5, 200, 15); UILabel *nameValue = [[UILabel alloc] initWithFrame:

nameValueRect]; nameValue.tag = kNameValueTag; [self.contentView addSubview:nameValue];

CGRect colorValueRect = CGRectMake(80, 25, 200, 15); UILabel *colorValue = [[UILabel alloc] initWithFrame:

colorValueRect]; colorValue.tag = kColorValueTag; [self.contentView addSubview:colorValue];

}

return self;

}

That should be pretty straightforward. We create four UILabels and add them to the table view cell. The table view cell already has a UIView subview called contentView, which it uses to group all of its subviews, much the way we grouped those two switches inside a UIView back in Chapter 4. As a result, we don’t add the labels as subviews directly to the table view cell, but rather to its contentView.

[self.contentView addSubview:colorValue];

www.it-ebooks.info

CHAPTER 8: Introduction to Table Views

239

Two of these labels contain static text. The label nameLabel contains the text Name:, and the label colorLabel contains the text Color:. Those are just labels that we won’t change. But we’ll use the other two labels to display our row-specific data. Remember that we need some way of retrieving these fields later on, so we assign values to both of them. For example, we assign the constant kNameValueTag to nameValue‘s tag field.

nameValue.tag = kNameValueTag;

Now, to put the finishing touches on the BIDNameAndColorCell class, add these two setter methods just before the @end:

- (void)setName:(NSString *)n {

if (![n isEqualToString:name]) { name = [n copy];

UILabel *nameLabel = (UILabel *)[self.contentView viewWithTag: kNameValueTag];

nameLabel.text = name;

}

}

- (void)setColor:(NSString *)c {

if (![c isEqualToString:color]) { color = [c copy];

UILabel *colorLabel = (UILabel *)[self.contentView viewWithTag: kColorValueTag];

colorLabel.text = color;

}

}

You already know that using @synthesize, as we did at the top of the file, creates getter and setter methods for each property. Yet, here we’re defining our own setters for both name and color! As it turns out, this is just fine. Any time a class defines its own getters or setters, those will be used instead of the default methods that @synthesize provides. In this class, we’re using the default, synthesized getters, but defining our own setters, so that whenever we are passed new values for the name or color properties, we update the labels we created earlier.

Implementing the Controller’s Code

Now, let’s set up the simple controller to display values in our nice new cells. Start off by selecting BIDViewController.h, where you need to add the following code:

#import <UIKit/UIKit.h>

@interface BIDViewController : UIViewController

<UITableViewDataSource, UITableViewDelegate>

@property (strong, nonatomic) NSArray *computers;

@end

In our controller, we need to set up some data to use, and then implement the table data source methods to feed that data to the table. Switch to BIDViewController.m, and add the following code at the beginning of the file:

www.it-ebooks.info

240CHAPTER 8: Introduction to Table Views

#import "BIDViewController.h"

#import "BIDNameAndColorCell.h"

@implementation ViewController

@synthesize computers;

.

.

.

- (void)viewDidLoad { [super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

NSDictionary *row1 = [[NSDictionary alloc] initWithObjectsAndKeys: @"MacBook", @"Name", @"White", @"Color", nil];

NSDictionary *row2 = [[NSDictionary alloc] initWithObjectsAndKeys: @"MacBook Pro", @"Name", @"Silver", @"Color", nil];

NSDictionary *row3 = [[NSDictionary alloc] initWithObjectsAndKeys: @"iMac", @"Name", @"Silver", @"Color", nil];

NSDictionary *row4 = [[NSDictionary alloc] initWithObjectsAndKeys: @"Mac Mini", @"Name", @"Silver", @"Color", nil]; NSDictionary *row5 = [[NSDictionary alloc] initWithObjectsAndKeys:

@"Mac Pro", @"Name", @"Silver", @"Color", nil];

self.computers = [[NSArray alloc] initWithObjects:row1, row2, row3, row4, row5, nil];

}

.

.

.

Of course, we need to be good memory citizens, so make the following changes to the existing viewDidUnload method:

- (void)viewDidUnload { [super viewDidUnload];

//Release any retained subviews of the main view.

//e.g. self.myOutlet = nil;

self.computers = nil;

}

Then add this code at the end of the file, above the @end declaration:

.

.

.

#pragma mark -

#pragma mark Table Data Source Methods

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.computers count];

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellTableIdentifier = @"CellTableIdentifier";

BIDNameAndColorCell *cell = [tableView dequeueReusableCellWithIdentifier:

www.it-ebooks.info

CHAPTER 8: Introduction to Table Views

241

CellTableIdentifier];

if (cell == nil) {

cell = [[BIDNameAndColorCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellTableIdentifier];

}

NSUInteger row = [indexPath row];

NSDictionary *rowData = [self.computers objectAtIndex:row];

cell.name = [rowData objectForKey:@"Name"]; cell.color = [rowData objectForKey:@"Color"];

return cell;

}

@end

This version of viewDidLoad creates a series of dictionaries. Each dictionary contains the name and color information for one row in the table. The name for that row is held in the dictionary under the key Name, and the color is held under the key Color. We stick all the dictionaries into a single array, which is our data for this table.

NOTE: Remember when Macs came in different colors, like beige, platinum, black, and white? And that’s not to mention the original iMac and MacBook series, with their beautiful rainbow

hues assortment. Now there’s just one color: silver. Harrumph.

Let’s focus on tableView:cellForRowWithIndexPath:, since that’s where we’re really getting into some new stuff. The first two lines of code are nearly identical to our earlier versions. We create an identifier and ask the table to dequeue a table view cell if it has one. The only difference here is that we declare the cell variable to be an instance of our BIDNameAndColorCell class instead of the standard UITableViewCell. That’s so we can access the properties that we added specifically to our table view cell subclass.

If the table doesn’t have any cells available for reuse, we need to create a new cell. This is essentially the same technique as before, except that here we’re also using our custom class instead of UITableViewCell. We specify the default style, although the style actually doesn’t matter, because we’ll be adding our own subviews to display our data rather than using the provided ones.

cell = [[BIDNameAndColorCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellTableIdentifier];

Once we’re finished creating our new cell, we use the indexPath argument that was passed in to determine which row the table is requesting a cell for, and then use that row value to grab the correct dictionary for the requested row. Remember that the dictionary has two key/value pairs: one with name and another with color.

NSUInteger row = [indexPath row];

NSDictionary *rowData = [self.computers objectAtIndex:row];

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]