首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》10.4 UINavigationBar

关灯直达底部

Homepwner的UINavigationBar对象目前没有显示任何内容。下面先让UINavigationBar对象针对栈顶的UIViewController对象显示一个具有描述性的标题。

UIViewController对象有一个名为navigationItem的属性,类型为UINavigationItem。和UINavigationBar不同,UINavigationItem不是UIView的子类,不能在屏幕上显示。UINavigationItem对象的作用是为UINavigationBar对象提供绘图所需的内容。当某个UIViewController对象成为UINavigationController的栈顶对象时,UINavigationBar对象就会访问该UIViewController对象的navigationItem,获取和界面显示有关的内容,如图10-14所示。

图10-14 UINavigationItem

UINavigationItem对象默认是“空”的。要让UINavigationBar对象能够显示最基本的信息,可以为UINavigationItem对象设置一个简单的标题(title属性)。当应用将某个UIViewController对象移至UINavigationController对象的栈顶时,UINavigationBar对象就会访问UIViewController对象的navigationItem属性,查看相应的title属性是否指向有效的NSString对象。如果是,就会在UINavigationBar对象的正中显示该字符串(见图10-15)。

图10-15 带标题的UINavigationItem对象

修改BNRItemsViewController.m中的init方法,将navigationItem的title属性设置为字符串Homepwner,代码如下:

- (instancetype)init

{

self = [super initWithStyle:UITableViewStylePlain];

if (self) {

UINavigationItem *navItem = self.navigationItem;

navItem.title = @“Homepwner”;

}

return self;

}

构建并运行应用。UINavigationBar对象会显示标题Homepwner。添加一个新的表格行并选中,UINavigationBar对象的标题会消失,所以下面要为BNRDetailViewController对象也设置一个“导航栏标题”,使用的字符串是选中的BNRItem对象的name属性。和BNRItemsViewController不同的是,不能在BNRDetailViewController的init方法中设置标题,因为这时的item属性还没有赋值,是nil。

正确的做法是在设置BNRDetailViewController对象的item属性时,设置相应的导航栏标题。在BNRDetailViewController.m中实现setItem:,替换掉编译器为item属性合成的存方法,代码如下:

- (void)setItem:(BNRItem *)item

{

_item = item;

self.navigationItem.title = _item.itemName;

}

构建并运行应用,添加一个新的表格行并选中。UINavigationBar对象会显示选中的BNRItem对象的name属性。

UINavigationItem对象除了可以设置标题字符串(title属性)外,还可以设置若干其他的界面属性,如图10-16所示。这些可以自定义的属性包括:leftBarButtonItem、rightBarButtonItem和titleView。其中leftBarButtonItem和rightBarButtonItem都是指向UIBarButtonItem对象的指针,该对象包含显示某种特殊按钮所需的信息,这种按钮只能在UINavigationBar对象或UIToolbar对象中使用。

图10-16 设置了各种界面属性的UINavigationItem对象

类似于UINavigationItem,UIBarButtonItem也不是UIView的子类。UINavigationItem对象封装了一些设置信息,以便UINavigationBar在运行时可以正确显示该对象。同样,UIBarButtonItem对象封装了关于如何在UINavigationBar显示单个按钮的信息,UINavigationBar对象会根据UIBarButtonItem对象中的信息显示相应的按钮。(UIToolbar与UINavigationBar一样,也是通过UIBarButtonItem对象来显示按钮的。)

除了leftBarButtonItem和rightBarButtonItem,UIBarButtonItem对象的第三个界面属性是titleView。UINavigationBar对象包含两种标题显示模式。第一种模式是前面介绍过的:显示一个简单的字符串。第二种模式是在UINavigationBar对象正中显示一个视图。两种模式不能共存。如果需要在UINavigationBar对象正中显示复杂的界面,就可以先创建拥有自定义视图(例如UIButton对象、UISlider对象、UIImageView对象甚至MKMapView对象)的视图控制器,然后为该对象的titleView赋值,并指向这个自定义视图。以图10-16中的UINavigationItem对象为例,该对象的titleView属性指向的就是一个自定义视图。通常情况下,使用第一种模式就可以了,本章使用的也是这种模式。

下面要让UINavigationBar对象显示一个按钮:当BNRItemsViewController对象位于栈顶时,在UINavigationBar对象的右端显示一个按钮。当用户点击这个按钮时,为UITableView对象添加一个新的表格行。

为了能在用户点击UINavigationBar对象中的按钮时触发指定的方法,必须为相应的UIBarButtonItem对象设置目标-动作对,其工作机制类似UIControl的目标-动作对。通过某个UIBarButtonItem对象的初始化方法和相应的存方法,都可以为该对象设置目标-动作对。

在BNRItemsViewController.m的init方法中,创建UIBarButtonItem对象并设置目标对象和动作方法,代码如下:

- (instancetype)init

{

self = [super initWithStyle:UITableViewStylePlain];

if (self) {

UINavigationItem *navItem = self.navigationItem;

navItem.title = @“Homepwner”;

// 创建新的UIBarButtonItem对象

// 将其目标对象设置为当前对象,将其动作方法设置为addNewItem:

UIBarButtonItem *bbi = [[UIBarButtonItem alloc]

initWithBarButtonSystemItem:UIBarButtonSystemItemAdd

target:self

action:@selector(addNewItem:)];

// 为UINavigationItem对象的rightBarButtonItem属性赋值,

// 指向新创建的UIBarButtonItem对象

navItem.rightBarButtonItem = bbi;

}

return self;

}

设置动作方法时,需要传入的参数类型是SEL。前文已经介绍过,SEL是指向选择器的指针,而选择器代表方法的整个方法名(包括所有的冒号)。@selector()不关心方法的返回类型、参数类型及参数名。

构建并运行应用。点击+按钮,UITableView对象会添加一个新的表格行(除了本节使用的initWithBarButtonSystemItem:target:action:,UIBarButtonItem还有多个其他初始化方法。详细内容请读者自行查阅文档)。

下面再为UINavigationBar对象添加一个按钮,用于替换掉表头视图中的Edit按钮。编辑BNRItemsViewController.m中的init方法,代码如下:

- (instancetype)init

{

self = [super initWithStyle:UITableViewStylePlain];

if (self) {

UINavigationItem *navItem = self.navigationItem;

navItem.title = @“Homepwner”;

// 创建新的UIBarButtonItem对象

// 将其目标对象设置为当前对象,将其动作方法设置为addNewItem:

UIBarButtonItem *bbi = [[UIBarButtonItem alloc]

initWithBarButtonSystemItem:UIBarButtonSystemItemAdd

target:self

action:@selector(addNewItem:)];

// 为UINavigationItem对象的rightBarButtonItem属性赋值,

// 指向新创建的UIBarButtonItem对象

navItem.rightBarButtonItem = bbi;

navItem.leftBarButtonItem = self.editButtonItem;

}

return self;

}

只需编写一行代码,向BNRItemsViewController对象发送editButtonItem消息,就能得到可以加入UINavigationBar对象的Edit(编辑)按钮。构建并运行应用,点击“编辑”按钮,UITableView对象会进入编辑模式。UIViewController对象有一个名为editButtonItem的属性,当该对象收到editButtonItem消息后,如果editButtonItem属性的值是nil,就会创建一个标题为“编辑”的UIBarButtonItem对象。此外,editButtonItem方法所返回的UIBarButtonItem对象默认已经设置好了目标-动作对。当用户点击对应的按钮时,包含该对象的UIViewController对象就会收到 setEditing:animated:消息。

为Homepwner的UINavigationBar对象添加“+”按钮和“编辑”按钮后,可以删除之前加入的那些和表头视图有关的代码。删除BNRItemsViewController.m中的以下代码:

- (UIView *)headerView

{

if (!_headerView){

[[NSBundle mainBundle] loadNibNamed:@“HeaderView”

owner:self options:nil];

}

return _headerView;

}

- (IBAction)toggleEditingMode:(id)sender

{

if (self.isEditing) {

[sender setTitle:@“Edit” forState:UIControlStateNormal];

[self setEditing:NO animated:YES];

} else {

[sender setTitle:@“Done” forState:UIControlStateNormal];

[self setEditing:YES animated:YES];

}

}

最后请读者删除不再需要使用的headerView属性和HeaderView.xib文件。

构建并运行应用。Homepwner不会再显示表头视图,取而代之的是带两个按钮的UINavigationBar对象(见图10-17)。

图10-17 使用UINavigationBar的Homepwner