您的位置:首页 > 产品设计 > UI/UE

导航栏(UINavigationBar类与UINavigationBarDelegate协议)

2013-07-10 19:11 169 查看
UINavigationBar类

UINavigationBar类主要是为在分层的内容间进行导航而设计的。它通常位于屏幕的上方,即我们熟知的导航栏,它包含一个左按钮,一个标题和一个可选的右按钮。这两个按钮通常是UIBarButtonItem对象,不过我们也可以使用自定义的视图替代它们。为了在分层的内容间进行导航,处于下一层次内容时的导航栏至少要包含一个左按钮,否则就无法从当前层返回到上一层。

通常,导航栏一般与导航视图控制器一同工作,控制器下容纳当前显示内容,控制器的上方则为导航栏。当然,我们也可以让导航栏独立工作,只需把它当做一般的视图加入到视图层次中。比如,我们可以在Interface Builder中的对象库中拖出一个Navigation Bar, 然后再同视图的其他部分一同加载。或者使用标准的alloc和initWithFrame方法以编程的方式创建Navigation Bar。当我们把Navigation Bar作为单件使用时,我们必须负责为其提供它包含的Button。不像其它的视图,我们不能直接向Bar添加字视图。相反,我们需要把Button添加到一个导航项(UINavigationItem类的实例)上,然后把这个导航项添加到Navigation
Bar上。有趣的是,导航项包含了两个属性,它们是leftBarButton和rightBarButton。前两个属性可以很明显地告诉我们,导航项可以拥有两个Button,左面一个,右面一个。这是千真万确的,可以在Interface Builder中验证一下,从对象库中拖出一个Bar Button Item 方在Navigation Item上,拖出的Button要么被放置在Navigation
Item的左面,要么就是右面。当左右都放置了Button后,就不会再放置第三个Button在Navigation Item上,相反,这会替换左面或右面已有的Button。因此,这种现象便说明了为什么导航项只有leftBarButton,rightBarButton属性,而没有centerBarButton等多余的Button属性。其实,从Navigation
Bar的应用角度来讲,导航项上左右两侧各有一个Button已经足够了。比如,左面的Button起到返回上层内容的作用,右侧的Button起到编辑当前内容的作用。

Navigation Bar有三个可以控制其外观的属性,它们分别是barStyle,tintColor和translucent。它们不但影响Bar的外观,也影响了位于其上Button的外观。

导航栏管理着一组UINavigationItem对象。位于堆栈最顶端的UINavigationItem对象代表导航栏正在显示的导航项,因此位于最顶端的导航项才能相应用户的操作。可以使用pushNavigationItem:animated:方法向堆栈内推入新的UINavigationItem对象,而使用popNavigationItemAnimated:方法从堆栈弹出UINavigationItem对象。除了直接推入和弹出导航项,我们还可以使用导航栏的item属性或者是setItem:animated:方法来直接地设置堆栈的内容。

UINavigationBarDelegate协议

UINavigationBarDelegate协议定义了几个可选的方法,UINavigation委托应该实现它们以在导航项被推入堆栈和从堆栈里被弹出时来更新它的视图。通过实现navigationBar:shouldPushItem:和navigationBar:shouldPopItem:方法,我们就可以控制某个导航项是否应该被推入或弹出堆栈。

我们还可以实现navigationBar:didPushItem:方法来更新导航栏下面的视图以响应新的导航项。类似地,实现navigationBar:didPopItem:方法来替换导航栏下面的视图。这两个方法都是在导航项被推入或被弹出的动作完成时才会被调用的,但前提是因被执行动作的导航而触发的navigationBar:shouldPushItem:和navigationBar:shouldPopItem:方法返回YES。

何时为NavigationBar指定委托对象?

如果把导航栏作为一个单件使用,我们应该创建一个遵循UINavigationBarDelegate协议的委托对象并将其赋给UINavigationBar对象的delegate属性,然后通过该对象来解释来自导航栏的信息。

如果我们导航栏是通过导航视图控制器(UINavigationViewController)被创建的,那么我们最好不要再对delegate属性进行赋值了。因为此时的导航栏是由控制器来管理的,它就是该导航栏的委托对象,它会全权负责导航项的推入和弹出,以及相应的视图更新工作。它所作的工作比我们做的更有效率,同时也为我们省去了很多代码。

下面,我们创建一个简单的应用来演示如何把导航栏作为单件来使用,它将以编程的方式被创建。在该应用中,我们通过点击导航栏上的第一个导航项右侧的添加按钮将第二个导航项添加到栈顶,然后可以在当前窗口进行文本编辑,最后通过点击当前导航项左侧的返回按钮将该导航项由栈顶弹出,回到第一个导航项。

备注:该工程使用Xcode 4.6.2 (4H1003)版本创建,目标iOS SDK版本为6.1,并使用了自动引用计数。同时,该实例并没有考虑实际应用的需要,仅作学习参考使用。

首先,通过向导创建一个Single View Application工程,命名为UINavigationBarSample, 设Project Prefix为WJF。创建完成后的工程结构如下:



接着,修改WJFViewController.xib。首先从对象库中拖出一个Navigation Bar放在视图view的顶部,并将其里面的Navigation Item删除。然后,再拖出一个Text View并占据view剩下的全部空间并选中它,在右侧的属性检查器中找到Text
View组合框,删除Text下的初始文本。最后,再找到View组合框,将Interaction右侧的User Interaction Enable上的钩去掉。修改后的xib如下:



然后,修改WJFViewController.h和WJFViewController.m文件。

WJFViewController.h文件

//
//  WJFViewController.h
//  UINavigationBarSample
//
//  Created by jiafu wan on 7/6/13.
//  Copyright (c) 2013 jiafu wan. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface WJFViewController : UIViewController<UINavigationBarDelegate>
@property (weak, nonatomic) IBOutlet UINavigationBar *navigationBar;
@property (strong, nonatomic)UINavigationItem *firstNavigationItem, *secondNavigationItem;
@property (strong,nonatomic) UIBarButtonItem *addButton, *editButton;
@property (weak, nonatomic) IBOutlet UITextView *textView;
-(void)addNote;
-(void)backToBrowse;
@end


WJFViewController类遵循UINavignonDelegate,并声明了两个输出口属性与xib文件内的视图对象进行关联。

WJFViewController.m文件
//
//  WJFViewController.m
//  UINavigationBarSample
//
//  Created by jiafu wan on 7/6/13.
//  Copyright (c) 2013 jiafu wan. All rights reserved.
//

#import "WJFViewController.h"

@interface WJFViewController ()

@end

@implementation WJFViewController
@synthesize navigationBar, firstNavigationItem, secondNavigationItem, addButton, editButton, textView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStyleBordered target:self action:@selector(backToBrowse)];
editButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(addNote)];
addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addNote)];
firstNavigationItem  = [[UINavigationItem alloc] initWithTitle:@"Note"];
secondNavigationItem = [[UINavigationItem alloc] initWithTitle:@"Edit"];
secondNavigationItem.leftBarButtonItem = backButton;
firstNavigationItem.rightBarButtonItem = addButton;
[navigationBar pushNavigationItem:firstNavigationItem animated:FALSE];
navigationBar.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)addNote
{
[navigationBar pushNavigationItem:secondNavigationItem animated:TRUE];
}
-(void)backToBrowse
{
if ([self.textView.text length] > 0)
self.navigationBar.backItem.rightBarButtonItem = editButton;
else
self.navigationBar.backItem.rightBarButtonItem = addButton;
[navigationBar popNavigationItemAnimated:TRUE];
[self.textView resignFirstResponder];
}
#pragma mark - delegate methods
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPushItem:(UINavigationItem *)item
{
return TRUE;
}
- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item
{
[self.textView becomeFirstResponder];
}
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
return TRUE;
}
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item
{

}
@end

在-viewDidLoad方法内我们创建了两个导航项,并分别为它们设置了右按钮和左按钮。-addNote方法内将新的导航项加入到栈顶,-backToBrowse方法将栈顶导航项弹出,同时还对新的栈顶导航项进行更新,它根据TextView是否有内容来设置新的右按钮,并让TextView放弃第一响应。最后面是四个重写的协议类方法,在恰当的时机我们让TextView成为第一响应者。

值得注意的是,我们不能在-navigation:didPopItem:方法内通过navigationBar的backItem和firstItem属性来更新导航项,因为此时这两个属性值是空的。可能是因为-navigation:didPopItem:方法是导航项间切换过程中的一分部,此时对backItem和firstItem的访问可能是危险的行为。不过在此期间我们还是可以直接对保存它们的实例变量进行访问,而为了使用navigationBar的backItem和firstItem属性,应该在导航栏切换前后使用它们。在-backToBrowse方法内,在调用-popNavigationItemAnimated:之前,使用backItem属性。如果在-popNavigationItemAnimated:之后,则应该使用firstItem属性。因为,firstItem指的是栈顶的导航项,而backItem则是栈顶之下与之最临近的导航项(如果存在)。

好了,一切准备就绪后,编译并运行这个应用吧!

点击添加按钮,导航项切换。


 

进行文本编辑,点击返回按钮进行浏览。


 

导航项切换,并将添加按钮改为编辑按钮。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息