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

CHAPTER 9: Navigation Controllers and Table Views

349

Figure 9–22. Our sixth and final subcontroller presents a list of US presidents. Tap one of the presidents, and you’ll be taken to a detail view (or a secret service agent will wrestle you to the ground).

Tapping any of the rows will take you down to the detail view that we just built (see Figure 9–8), and you’ll be able to edit the values. If you select the Done button in the keyboard, the keyboard should retract. Tap one of the editable values, and the keyboard will reappear. Make some changes and tap Cancel, and the application will pop back to the list of presidents. If you revisit the president you just canceled out of, your changes will be gone. On the other hand, if you make some changes and tap Save, your changes will be reflected in the parent table, and when you come back into the detail view, the new values will still be there.

But There’s One More Thing. . .

There’s one more bit of polish we need to add to make our application behave the way it should. In the version we just built, the keyboard incorporates a Done button that, when tapped, makes the keyboard retract. That behavior is proper if there are other controls on the view that the user might need to access. Since every row on this table view is a text field, however, we need a slightly different solution. The keyboard should feature a Return button instead of a Done button. When tapped, that button should take the user to the next row’s text field.

www.it-ebooks.info

350

CHAPTER 9: Navigation Controllers and Table Views

In order to accomplish this, our first step is to replace the Done button with a Return button. We can do this by deleting a single line of code from

BIDPresidentDetailController.m. In the tableView:cellForRowAtIndexPath: method, delete the following line of code:

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

static NSString *PresidentCellIdentifier = @"PresidentCellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:

PresidentCellIdentifier]; if (cell == nil) {

cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:PresidentCellIdentifier];

UILabel *label = [[UILabel alloc] initWithFrame: CGRectMake(10, 10, 75, 25)];

label.textAlignment = UITextAlignmentRight; label.tag = kLabelTag;

label.font = [UIFont boldSystemFontOfSize:14]; [cell.contentView addSubview:label];

UITextField *textField = [[UITextField alloc] initWithFrame: CGRectMake(90, 12, 200, 25)];

textField.clearsOnBeginEditing = NO; [textField setDelegate:self]; textField.returnKeyType = UIReturnKeyDone; [textField addTarget:self

action:@selector(textFieldDone:)

forControlEvents:UIControlEventEditingDidEndOnExit]; [cell.contentView addSubview:textField];

}

NSUInteger row = [indexPath row];

...

The next step isn’t quite as straightforward. In our textFieldDone: method, instead of simply telling sender to resign first responder status, we need to somehow figure out what the next field should be and tell that field to become the first responder. Replace your current version of textFieldDone: with the following new version, and then we’ll chat about how it works.

- (IBAction)textFieldDone:(id)sender { UITableViewCell *cell =

(UITableViewCell *)[[sender superview] superview]; UITableView *table = (UITableView *)[cell superview]; NSIndexPath *textFieldIndexPath = [table indexPathForCell:cell]; NSUInteger row = [textFieldIndexPath row];

row++;

if (row >= kNumberOfEditableRows) { row = 0;

}

NSIndexPath *newPath = [NSIndexPath indexPathForRow:row inSection:0]; UITableViewCell *nextCell = [self.tableView

cellForRowAtIndexPath:newPath]; UITextField *nextField = nil;

for (UIView *oneView in nextCell.contentView.subviews) {

www.it-ebooks.info

CHAPTER 9: Navigation Controllers and Table Views

351

if ([oneView isMemberOfClass:[UITextField class]]) nextField = (UITextField *)oneView;

}

[nextField becomeFirstResponder];

}

Unfortunately, cells don’t know which row they represent. The table view, however, does know which row a given cell is currently representing. So, we get a reference to the table view cell. We know that the text field that is triggering this action method is a subview of the table cell view’s content view, so we just need to get sender’s superview’s superview (now say that ten times fast).

If that sounded confusing, think of it this way: In this case, sender is the text field being edited. Our sender’s superview is the content view that groups the text field and its label. And sender’s superview’s superview is the cell that encompasses that content view.

UITableViewCell *cell = (UITableViewCell *)[[(UIView *)sender superview] superview];

We also need access to the cell’s enclosing table view, which is easy enough, since it’s the superview of the cell.

UITableView *table = (UITableView *)[cell superview];

We then ask the table which row the cell represents. The response is an NSIndexPath, and we get the row from that.

NSIndexPath *textFieldIndexPath = [table indexPathForCell:cell];

NSUInteger row = [textFieldIndexPath row];

Next, we increment row by one, which represents the next row in the table. If incrementing the row number puts us beyond the last one, we reset row to 0.

row++;

if (row >= kNumberOfEditableRows) { row = 0;

}

Then we build a new NSIndexPath to represent the next row, and use that index path to get a reference to the cell currently representing the next row.

NSIndexPath *newPath = [NSIndexPath indexPathForRow:row inSection:0]; UITableViewCell *nextCell = [self.tableView

cellForRowAtIndexPath:newPath];

Note that instead of using alloc and init methods to create the NSIndexPath, we’re using a special factory method that exists just for the purpose of creating an index path that points out a row in a UITableView. The normal way of creating an NSIndexPath otherwise involves first creating a C array, and then passing it to the initWithIndexes:length: method along with the length of the array. What we’re doing here is much more straightforward.

For the text field, we’re already using tag for another purpose, so we need to loop through the subviews of the cell’s content view to find the text field rather than using tag to retrieve it.

www.it-ebooks.info

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