第09章 导航控制器和表视图

总结:

其实navigationController很简单,其往往就是应用程序委托的根视图控制器

且其往往就是通过第一个显示的视图控制器来初始化自己。

而后的工作,就是pushViewController,popViewController。。。

[self.navigationController   pushViewController: controller animated:YES];

[self.navigationController popViewController Animated: YES];

表视图也很简单,只要实现其特定的数据源方法,委托方法,即可实现。

numberOfRowsInSection

cellForRowAtIndexPath

通过cell.accessoryType,cell.accessoryView控制其显示类型。

通过editingStyleForRowAtIndexPath的返回值来控制编辑类型(移动或删除插入)

实现委托方法moveRowAtIndexPath:toIndexPath:实现移动

实现委托方法commitEditingStyle:forRowAtIndexPath:实现插入删除

对比第8章内容:

UITableViewController,内建有一个UITableView,无需xib文件

如果需要自定义cell样式,可在dequeue获取cell后,向其contentsView addSubView

而如果是自定义的Controller,关联一个xib,其中有一个UITableView

此时,如果要自定义Cell样式,有两种方法:

1.代码方式,创建UITableViewCell子类,在其init中添加子视图,

在controller中的viewDidLoad中为此cell registerClass,进而可以获取到该类型的cell

2.xib方式,创建一个xib,包含一个UITableViewCell, 利用IB修改界面

然后在controller中的viewDidLoad中为此cell registerNib,进而可以获取到该类型的cell

疑问:那为啥不像本章例子一样,直接在Controller的cellForRowAtIndexPath中,

获取常规的Cell后,再向其contentsView addSubView?难道是为了Cell的复用考虑?

==========================================================================

stack:

base:第一个压入栈的对象,栈底

top:最后一个压入栈的对象,栈顶

push:压栈

pop:弹出

导航控制器维护着一个控制器栈。

title是当前栈顶controller的title属性

左边button是上一个controller的title属性,

如果点击,则会返回该controller,相当于将当前的栈顶弹出。

accessory icons:通常有以下两种类型

disclosure indicator :右侧灰色小箭头

detail disclosure button:右侧细节按钮(选择该行会触发一个动作;点击该按钮,会触发另外一个动作。)

这两种为默认的右侧视图,还可以通过cell.detailView定制自己的控件

when to use disclosure indicators and detail disclosure buttons:

If you want to offer a single choice for a row tap, don‘t use an accessory icon if a row tap will only lead to a more detailed view of that row.

如果点击该行,只会看到该行的细节,而不会引导到另一个view,则不要使用accessory icon(无右侧视图)

Mark the row with a disclosure indicator (gray arrow) if a row tap will lead to a new view (nota detail view).

如果点击该行,会引导到另外一个view(不是细节视图),则使用disclosure indicator(灰色箭头)

If you want to offer two choices for a row, mark the row with a detail disclosure button.

This allows the user to tap on the row for a new view or the disclosurebutton for more details.

如果想实现两种,则使用detail disclosure button,点击该行,会引导到另一个视图。点击该按钮,会显示细节。

accessory view

usually holds the accessory icon 通常包含accessory icon

不过也能此view上实现更多功能。

第一种:accessory icons

第二种:check mark

第三种:accessory view

第四种:move

第五种:delete

第六种:editable detail

The Nav Application’s Skeleton

command+shift+N创建工程

command+N创建文件

When we subclass UITableViewController, we inherit some nice functionality from that class that will create a table view with no need for a nib file.

apple提供的UITableViewController中,已经包含了一个UITableView,无需nib文件

1.创建空工程

2.创建类BIDFirstLevelViewController继承自UITableViewController

3.用此控制器作为一级视图,创建导航控制器,并将导航控制器设置为应用程序委托的根视图控制器

BIDFirstLevelViewController *first = [[BIDFirstLevelViewController alloc] init];

UINavigationController *navigation = [[UINavigationController alloc]  initWithRootViewController :first];

self.window.rootViewController = navigation;

使用一级视图BIDFirstLevelViewController 作为初始视图来创建构造导航控制器

导航控制器作为应用程序窗口的根视图

第二级viewcontroller,继承自UITableViewController,拥有一个UIImage

@interface BIDSecondLevelViewController : UITableViewController

@property (strong, nonatomic) UIImage *rowImage;

@end

第一级viewcontroller,继承自UITableViewController,拥有一个二级viewController数组

@interface BIDFirstLevelViewController : UITableViewController

@property (copy, nonatomic) NSArray *controllers; //一系列二级controllers

@end

使用数据源方法获取cell的时候,根据第二级视图的title和image,赋值cell属性

// Configure the cell...

BIDSecondLevelViewController *controller = self.controllers[indexPath.row];

cell.textLabel.text = controller.title;

cell.imageView.image = controller.rowImage;

使用委托方法,当点击一级视图的某行,navi到某一个二级视图

注意,怎么通过一级视图,获取到其导航控制器

- (void)tableView:(UITableView *)tableView

didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

BIDSecondLevelViewController *controller = self.controllers[indexPath.row];

[self.navigationController   pushViewController: controller animated:YES];

}

self.navigationController这个属性何时被赋值的?难道是使用一级视图构建导航控制器的时候??

创建第一个二级视图控制器

创建BIDDisclosureButtonViewController继承自BIDSecondLevelViewCont

cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;

@property (copy, nonatomic) NSArray *movies; //显示的不同行

@property (strong, nonatomic) BIDDisclosureDetailViewController *detailController; //保持的细节展示视图,为了复用

控制器的初始化

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

// Custom initialization

self.title = @"Disclosure Buttons";

self.rowImage = [UIImage imageNamed:@"disclosureButtonControllerIcon.png"];

self.movies = @[@"Toy Story", @"A Bug’s Life", @"Toy Story 2",

@"Monsters, Inc.", @"Finding Nemo", @"The Incredibles",

@"Cars", @"Ratatouille", @"WALL-E", @"Up",

@"Toy Story 3", @"Cars 2", @"Brave"];

self.detailController = [[BIDDisclosureDetailViewController alloc] init];

}

return self;

}

记得为该表视图控制器注册可复用表视图单元

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view.

[self.tableView registerClass:[UITableViewCell class]

forCellReuseIdentifier: CellIdentifier]; //为什么都是同一个字符串?底层难道也会为不同的控制器维护不同的队列?

}

数据源方法

#pragma mark - Table View Data Source Methods

- (NSInteger)tableView:(UITableView *)tableView

numberOfRowsInSection:(NSInteger)section

{

return [self.movies count];

}

- (UITableViewCell *)tableView:(UITableView *)tableView

cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

UITableViewCell *cell = [tableView  dequeueReusableCellWithIdentifier:CellIdentifier];

cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;  //detail disclosure button 类型

cell.textLabel.text = self.movies[indexPath.row];

return cell;

}

委托方法

- (void)tableView:(UITableView *)tableView

didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

UIAlertView *alert = [[UIAlertView alloc]

initWithTitle:@"Hey, do you see the disclosure button?"

message:@"Touch that to drill down instead."

delegate:nil

cancelButtonTitle:@"Won’t happen again"

otherButtonTitles:nil];

[alert show];

} //点击该行时,弹出警告视图

点击detail disclosure button

- (void)tableView:(UITableView *)tableView

accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath

{

NSString *selectedMovie = self.movies[indexPath.row];

NSString *detailMessage = [[NSString alloc]  initWithFormat:@"This is details for %@.", selectedMovie];

self.detailController.message = detailMessage;

self.detailController.title = selectedMovie;

[self.navigationController pushViewController: self.detailController  animated:YES];

//在导航视图中,所有需要显示的视图,都采用pushViewController方法

}

细节视图控制器=========================================================

创建无xib文件,继承自UIViewController的用于展示细节的控制器BIDDisClosureDetailViewController

在修改loadView,让Controller的view为一个UILabel

@interface BIDDisclosureDetailViewController : UIViewController

@property (weak, readonly, nonatomic) UILabel *label;

@property (copy, nonatomic) NSString *message;

@end

readonly 只有getter,没有setter

- (UILabel *)label;

{

return (id)self.view;

}

- (void)loadView;

{

UILabel *label = [[UILabel alloc] init];

label.numberOfLines = 0;  //这样即可显示任意多行的文本

label.textAlignment = NSTextAlignmentCenter;

self.view = label;

}

- (void)viewWillAppear:(BOOL)animated;

{

[super viewWillAppear:animated];

self.label.text = self.message;

}

此控制器的view,就是一个全屏的uilabel

注意,loadView和viewDidLoad只会在第一次加载视图的时候调用,

如果我们打算只初始化一次此Controller,那么需要在viewWillAppear中更新显示的数据

因为当第一次显示此细节展示控制器时候的时候,已经进行了loadView和viewDidLoad

而且此控制器是被二级视图控制器保持着的,并不会被释放。

所以需要在viewWillAppear中更新uilabel显示的内容。

这样,以上显示细节视图控制器,就可以被复用,

当点击不同的cell的accessory button的时候,显示出来的其实是同一个detail viewcontroller

细节视图控制器=========================================================

第二个视图控制器 BIDCheckListViewController

cell.accessoryType = UITableViewCellAccessoryCheckmark;

@property (assign, noatomic) NSUInteger selectedSnack;  //记录被选中的行

其实很简单,在获取cell的时候

if (self.selectedSnack == indexPath.row) {

cell.accessoryType = UITableViewCellAccessoryCheckmark;

} else {

cell.accessoryType = UITableViewCellAccessoryNone;

}

然后在didSelectRowAtIndexPath委托中,记得去掉之前选中的状态

- (void)tableView:(UITableView *)tableView

didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

if (indexPath.row != self.selectedSnack) {

if (self.selectedSnack != NSNotFound) {

NSIndexPath *oldIndexPath = [NSIndexPath indexPathForRow:self.selectedSnack  inSection:0];

UITableViewCell *oldCell = [tableView cellForRowAtIndexPath: oldIndexPath];

oldCell.accessoryType = UITableViewCellAccessoryNone;

}

UITableViewCell *cell = [tableView cellForRowAtIndexPath :indexPath];

cell.accessoryType = UITableViewCellAccessoryCheckmark;

self.selectedSnack = indexPath.row;

}

//反选,去掉高亮,因为已经check mark了

[tableView deselectRowAtIndexPath: indexPath animated:YES];

}

第三个视图控制器BIDRowControlsViewController

cell.accessoryView = button;

- (UITableViewCell *)tableView:(UITableView *)tableView

cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

cell.textLabel.text = self.characters[indexPath.row];

if (cell.accessoryView == nil) {

UIImage *buttonUpImage = [UIImage imageNamed:@"button_up.png"];

UIImage *buttonDownImage = [UIImage imageNamed:@"button_down.png"];

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

[button setBackgroundImage:buttonUpImage

forState:UIControlStateNormal];

[button setBackgroundImage:buttonDownImage

forState:UIControlStateHighlighted];

[button setTitle:@"Tap" forState:UIControlStateNormal];

[button sizeToFit];

[button addTarget: self

action: @selector(tappedButton:)

forControlEvents: UIControlEventTouchUpInside];

cell.accessoryView = button;

}

//设置button tag,以备后用

cell.accessoryView.tag = indexPath.row;

return cell;

}

注意accessoryType和accessoryView

前者通过几个预定义类型,显示预定义视图,

后者可以设置为任何视图。

第四个视图控制器Movable Rows

editing mode

which is done using the setEditing:animated: method on the table view.

Once editing mode is turned on, a number of new delegate methods come into play.

@property (strong, nonatomic) NSMutableArray *words;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

// Custom initialization

self.title = @"Move Me";

self.rowImage = [UIImage imageNamed:@"moveMeIcon.png"];

self.words = [@[@"Eeny", @"Meeny", @"Miney", @"Moe", @"Catch", @"A",

@"Tiger", @"By", @"The", @"Toe"] mutableCopy];

self. navigationItem. rightBarButtonItem = self.editButtonItem;

}

return self;

}

self.navigationController

self.navigationItem.rightBarButtonItem

self.editButtonItem

All UIViewControllersub classes have an editButtonItem property that provide a default

bar item button for toggling its editing state. For a UITableViewController subclass like

BIDMoveMeViewController, this button will toggle the editing state of the UITableView using the

setEditing:animated: method。

所有的UIViewController子类,都有个editButtonItem,其用来翻转视图的editing state

UITableViewController 的此editButtonItem采用setEditing:animated: 方法,来翻转其tableView的editing state

注意,edit是指删除和插入新行

新的委托方法

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView

editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath

{

return UITableViewCellEditingStyleNone;

}//注意,这里的editingStyle是指删除,或者插入新行,

默认为delete,所以只支持移动的话,需要实现此委托,返回None

- (BOOL)tableView:(UITableView *)tableView

shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath

{

return NO;

}

移动某行的时候,调用的是此委托方法

- (void)tableView:(UITableView *)tableView

moveRowAtIndexPath:(NSIndexPath *)fromIndexPath

toIndexPath:(NSIndexPath *)toIndexPath

{

id object = [self.words objectAtIndex:fromIndexPath.row];

[self.words removeObjectAtIndex:fromIndexPath.row];

[self.words insertObject:object atIndex:toIndexPath.row];

}

Creating the Deletable Rows View

删除更简单

- (void)tableView:(UITableView *)tableView

commitEditingStyle:(UITableViewCellEditingStyle)editingStyle

forRowAtIndexPath:(NSIndexPath *)indexPath //删除时,为删除的行。插入时,为插入的行

{

[self.computers removeObjectAtIndex:indexPath.row];

[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]

withRowAnimation:UITableViewRowAnimationAutomatic];

}

不允许编辑(删除,插入),即只允许移动

UITableViewCellEditingStyleNone: We used this style in the

previous controller to indicate that a row can’t be edited. The option

UITableViewCellEditingStyleNone will never be passed into this method

because it is used to indicate that editing is not allowed for this row.

默认为删除

UITableViewCellEditingStyleDelete: This is the default option. We ignore this

parameter because the default editing style for rows is the delete style, so we

know that every time this method is called, it will be requesting a delete. You can

use this parameter to allow inserts and deletes within a single table.

UITableViewCellEditingStyleInsert: This is generally used when you need

to let the user insert rows at a specific spot in a list. In a list whose order is

maintained by the system, such as an alphabetical list of names, the user will

usually tap a toolbar or navigation bar button to ask the system to create a new

object in a detail view. Once the user is finished specifying the new object, the

system will place it in the appropriate row.

第6个控制器,可编辑detail

Sixth Subcontroller: An Editable Detail Pane

Creating the Data Model Object

@interface BIDPresident : NSObject <NSCoding, NSCopying>

@property (assign, nonatomic) NSInteger number;

@property (copy, nonatomic) NSString *name;

@property (copy, nonatomic) NSString *fromYear;

@property (copy, nonatomic) NSString *toYear;

@property (copy, nonatomic) NSString *party;

@end

NSCoding协议

encodeWithCoder:

initWithCoder:

NSCopying协议

copyWithZone:

BIDPresidentsViewController subClass BIDSecondLevelViewController

BIDPresidentDetailViewController subClass UITableViewController 细节展示控制器

#import <UIKit/UIKit.h>

@class BIDPresident;

@protocol BIDPresidentDetailViewControllerDelegate;

@interface BIDPresidentDetailViewController : UITableViewController <UITextFieldDelegate>

@property (copy, nonatomic) BIDPresident *president; //data

@property (weak, nonatomic) id<BIDPresidentDetailViewControllerDelegate> delegate;//委托

@property (assign, nonatomic) NSInteger row; //选择的行

@property (strong, nonatomic) NSArray *fieldLabels;

- (IBAction)cancel:(id)sender;

- (IBAction)save:(id)sender;

- (IBAction)textFieldDone:(id)sender;

@end

//此协议,用来告诉其委托,数据已经修改,需要更新。

@protocol BIDPresidentDetailViewControllerDelegate <NSObject>

- (void)presidentDetailViewController:(BIDPresidentDetailViewController *)controller

didUpdatePresident:(BIDPresident *)president;

@end

NSString为何要用copy?而不是strong?

strong和retain同义, weak和assign同义, 为什么要采用这种说法, 似乎是ARC出现后为了消除引用计数的观念而采用的做法.

至于为什么要用copy, 由于纯NSString是只读的, 所以strong和copy的结果一样,据stackOverflow上的说法,是为了防止mutable string被无意中修改,

NSMutableString是NSString的子类, 因此NSString指针可以持有NSMutableString对象.

#define kNumberOfEditableRows 4

#define kNameRowIndex 0

#define kFromYearRowIndex 1

#define kToYearRowIndex 2

#define kPartyIndex 3

#define kLabelTag 2048

#define kTextFieldTag 4094

@implementation BIDPresidentDetailViewController {

NSString *initialText; //编辑前的初始值

BOOL hasChanges; //是否有修改

}

//表视图初始化

- (id)initWithStyle:(UITableViewStyle)style

{

self = [super initWithStyle: UITableViewStyleGrouped]; //强制为分组模式

if (self) {

// Custom initialization

self.fieldLabels = @[@"Name:", @"From:", @"To:", @"Party:"];

self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]

initWithBarButtonSystemItem: UIBarButtonSystemItemCancel 系统预定义按钮

target:self

action:@selector(cancel:)];

self.navigationItem.rightBarButtonItem =[[UIBarButtonItem alloc]

initWithBarButtonSystemItem: UIBarButtonSystemItemSave 系统预定义按钮

target:self

action:@selector(save:)];

}

return self;

}

//

- (void)viewDidLoad

{

[super viewDidLoad];

self.tableView.allowsSelection = NO;  //不允许选中

}

//取消

- (void)cancel:(id)sender

{

[self.navigationController popViewController Animated: YES];   //取消,则弹出

}

//保存

- (void)save:(id)sender

{

[self.view endEditing:YES];

if (hasChanges) {

[self.delegate presidentDetailViewController:self

didUpdatePresident:self.president];  //调用委托方法,让委托自己去更新数据

}

[self.navigationController popViewControllerAnimated:YES];

}

//完成输入,收缩键盘

//此方法为textField控件关联controller的Action,响应Did End On Exit事件

//注意其不是一个委托方法,仅仅是文本输入的事件响应

- (void)textFieldDone:(id)sender

{

[sender resignFirstResponder];

}

//

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

// Return the number of rows in the section.

return kNumberOfEditableRows;

}

//获取表视图单元

- (UITableViewCell *)tableView:(UITableView *)tableView

cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:

CellIdentifier];

if (cell == nil) {

cell = [[UITableViewCell alloc]

initWithStyle:UITableViewCellStyleDefault

reuseIdentifier:CellIdentifier];

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

label.tag = kLabelTag; //假如后面还需要获取该控件,则可以设置其tag

label.textAlignment = NSTextAlignmentRight;

label.font = [UIFont boldSystemFontOfSize:14];

[cell.contentView addSubview:label]; //直接在cell中添加子视图

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

textField.tag = kTextFieldTag;

textField.clearsOnBeginEditing = NO;

textField.delegate = self; //设置委托

textField.returnKeyType = UIReturnKeyDone;

[textField addTarget:self

action:@selector(textFieldDone:)

forControlEvents:UIControlEventEditingDidEndOnExit]; //输入完成,响应

[cell.contentView addSubview:textField];

}

UILabel *label = (id)[cell viewWithTag: kLabelTag];//通过Tag,再次获取label

label.text = self.fieldLabels[indexPath.row];

UITextField *textField = (id)[cell viewWithTag:kTextFieldTag]; //使用(id)做类型转换

textField.superview.tag = indexPath.row;  //设置tag,后面会用到

switch (indexPath.row) {

case kNameRowIndex:

textField.text = self.president.name;

break;

case kFromYearRowIndex:

textField.text = self.president.fromYear;

break;

case kToYearRowIndex:

textField.text = self.president.toYear;

break;

case kPartyIndex:

textField.text = self.president.party;

break;

default:

break;

}

return cell;

}

//textField委托方法,开始编辑

- (void)textFieldDidBeginEditing:(UITextField *)textField

{

initialText = textField.text;

}

//textField委托方法,完成编辑

- (void)textFieldDidEndEditing:(UITextField *)textField

{

if (![textField.text isEqualToString:initialText]) {

hasChanges = YES;

switch (textField.superview.tag) {

case kNameRowIndex:

self.president.name = textField.text;

break;

case kFromYearRowIndex:

self.president.fromYear = textField.text;

break;

case kToYearRowIndex:

self.president.toYear = textField.text;

break;

case kPartyIndex:

self.president.party = textField.text;

break;

default:

break;

}

}

}

@end

实现BIDPresidentsViewController

@interface BIDPresidentsViewController : BIDSecondLevelViewController <BIDPresidentDetailViewControllerDelegate>

@property (strong, nonatomic) NSMutableArray *presidents;

@end

@implementation BIDPresidentsViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

// Custom initialization

self.title = @"Detail Edit";

self.rowImage = [UIImage imageNamed:@"detailEditIcon.png"];

NSString *path = [[NSBundle mainBundle] pathForResource:@"Presidents"ofType:@"plist"];

NSData *data = [[NSData alloc] initWithContentsOfFile: path];

//archiver从文件获取对象

NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData: data];

self.presidents = [unarchiver decodeObjectForKey:@"Presidents"];

[unarchiver finishDecoding];

}

return self;

}

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view.

[self.tableView registerClass:[UITableViewCell class]forCellReuseIdentifier:CellIdentifier];

}

#pragma mark - Table View Data Source Methods

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

return [self.presidents count];

}

- (UITableViewCell *)tableView:(UITableView *)tableView

cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

BIDPresident *president = self.presidents[indexPath.row];

cell.textLabel.text = president.name;

return cell;

}

#pragma mark - Table View Delegate Methods

- (void)tableView:(UITableView *)tableView

didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

BIDPresident *president = self.presidents[indexPath.row];

BIDPresidentDetailViewController *controller = [[BIDPresidentDetailViewController alloc] init];

controller.president = president;

//注意BIDPresidentDetailViewController 的president属性为copy,

//意味着此赋值将创建一个独立的president,跟当前数组中的president不是同一份内存

//为什么必须为copy,因为在detailController中,textFiled编辑后,就会改写其维护的president对象,

//最终点取消则不会保存。

controller.delegate = self;

controller.row = indexPath.row;

[self.navigationController pushViewController:controller animated:YES];

}

//委托方法,需要更新president数据

#pragma mark - President Detail View Delegate Methods

- (void)presidentDetailViewController:(BIDPresidentDetailViewController *)controller

didUpdatePresident:(BIDPresident *)president

{

[self.presidents replaceObjectAtIndex: controller.row withObject:president];

[self.tableView reloadData];

}

@end

The keyboard should feature a Returnbutton instead of a Donebutton. When tapped, that button should take the user to the next row’s text field。

实现点击键盘return按钮,跳转到下一行。

- (void)textFieldDone: (id)sender

{

//[sender resignFirstResponder];

UITextField *senderField = sender;

NSInteger nextRow = (senderField.superview.tag + 1) % kNumberOfEditableRows;

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:nextRow inSection:0];

UITableViewCell *nextCell = [self.tableView cellForRowAtIndexPath:indexPath];

UITextField *nextField = (id)[nextCell viewWithTag:kTextFieldTag];

[nextField becomeFirstResponder];

}

时间: 2024-11-15 07:50:45

第09章 导航控制器和表视图的相关文章

【iOS开发-24】导航控制器下不同视图控制器之间切换:利用CATrasition和view的layer层来实现自定义的动画效果

(1)这里的动画效果指的是界面切换的动画效果,我们常见的又淡入淡出,右出左进等等,当然还有一些高级动画,这种动画适合游戏类的,对于一般APP会显得太花哨. (2)我们在此处没有增加任何框架(QuartzCore)也没有导入什么头文件(QuartzCore.h),就可以直接用CATransiton(相当于是CAAnimation的子类)来创建一个对象,如animation1. (3)创建完之后我们就对这个动画对象进行动画设置,这里面主要是涉及到type属性,而且值有两种:一种是调用系统自带的一些效

[BS-20] 导航控制器和视图控制器在添加控制器的区别

导航控制器和视图控制器在添加控制器的区别 1. 因导航控制器拥有导航栈,有一个普通视图控制器都没有的数组viewControllers,加入该数组中的视图控制器默认以push的方式进入导航栈.导航控制器有个[UINavigationController alloc] initWithRootViewController:rootVC]; 的初始化方法,调用该方法相当于把rootVC加入数组viewControllers的第一个位置,作为栈底部的rootVC是不会被pop出去的,与导航控制器共生死

找到导航控制器中当前所有的视图控制器

//   栈:只有一口 ,先进后出 :push 入栈 : pop 出栈 : //    队列:有两个口 ,先进先出: //导航控制器: 容器 :实现视图控制器界面之间的跳转 : UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:firstVC]; //当你把一个视图控制器放入导航控制器时,视图控制器的属性navigationController会被赋值,记录nav:所以

[菜鸟成长记]iOS开发自学笔记06-导航控制器和segue的传递数据

导航控制器通常用来显示分层内容的向下导航界面,受限于设备屏幕大小,iPhone或者iPad需要通过更多的层次访问来显示足够丰富的内容,导航控制器一般会和表视图同时存在,但不是说必须一起绑定使用,这里将表视图嵌入到导航控制器中用于分层显示视图内容,以single view application为模板建立一个project,打开Main.storyboard,点击view controller再在工具栏上点击editor->embed in->navigation controller将视图控制

视图控制器、模态视图

一.什么是试图控制器? 视图控制器就是用来管理视图的加载.卸载.横屏竖屏显示等操作的控制器. 每一个界面都会由一个控制器来管理显示 ,单独的界面view需要视图控制器这个载体来管理显示. UIViewController是所有视图控制器的父类 . iOS提供了许多内置的视图控制器类,以支持标准的用户界面部分,比如导航控制器 (UINavigationController),标签栏控制器(UITabBarController),表视图控制器 (UITableViewController)等 . 每

iOS开发-21UINavigationController导航控制器初始化 导航控制器栈的push和pop跳转理解

(1)导航控制器初始化的时候一般都有一个根视图控制器,导航控制器相当于一个栈,里面装的是视图控制器,最先进去的在最下面,最后进去的在最上面.在最上面的那个视图控制器的视图就是这个导航控制器对外展示的界面,也就是用户看到的界面. (2)我们需要把导航控制器加载到APP中,需要把这个导航控制器设置为window的根视图控制器(都是控制器类,可以赋值),这样就相当于加载到了window里. (3)我们要在栈中新增或者删除一个视图控制器,就需要得到导航控制器,一般在栈中得所有视图控制器都有一个self.

UINavigationController导航控制器

UINavigationController导航控制器,是多个界面间跳转的重要元素,可以理解为它存储着多个viewController,它的存储结构是栈,栈的特点是先进后出,所以添加视图控制器时,要特别注意. UINavigationController有几个常用的方法: 1:[UINavigationController initWithRootViewController:viewController ] 是指将哪一个视图控制器设置为导航控制器的根视图控制器,即运行是第一次看到的界面. 2:

UINavigationController 导航控制器

初始方法: - (id)initWithRootViewControl:(UIViewController *)rootViewController //初始化时,传递一个视图控制器的参数,作为导航控制器的根视图控制器,导航控制器实例加载完成后,根视图控制器的视图会被添加到导航控制器中 入栈操作: //从导航控制器某一个视图里面把另一个视图Push进导航控制器栈中. [self.navigationController pushViewController:(UIViewController *

ios入门笔记(导航控制器)

1.删除故事板中默认的视图控制器,和与之对应的.h.m文件 2.从对象库拖导航控制器对象到编辑器中(会好像加了两个场景) 3.添加两个类,第一个为UINavigationCOntroller子类关联到导航控制,第二个为UIViewCOntroller子类关联到根视图 和其他视图 (class是自己的命名,subclassof必须选择相应的父类) 4.关联完成后可以更改相应控制器的标签让其编程时更友好(这里的标签与底层的代码不关联) 5.导航控制器与视图控制器数据联系, 可在导航控制器.H中建立属