UINavigationController

导航控制器(UINavigationController)其本身的样式可供定制的内容并不是很多,但其主要作用在于容纳其他类型的控制器,并且实现不同控制器之间的跳转。学习导航控制器,最核心的知识在于掌握如何通过导航控制器实现控制器的跳转,以及如何定制导航栏样式。

内容类控制器(Content ViewController):所谓内容类控制器,主要用于显示内容,常见的有UIViewController,UITableViewController,UICollectionViewController等。
容器类控制器(Container ViewController):所谓容器型控制器,主要用于容纳其他内容类控制器,本身并不主要用于显示有用的内容,主要工作负责在不同控制器之间进行切换,常见的有UINavigationController,UITabBarController

导航控制器的创建既可以使用代码创建,也可以使用XIB或Storyboard创建。核心有3个步骤:

实例化一个控制器对象,例如一个UIViewController类的对象,作为导航控制器对象的根控制器rootViewcontroller。
实例化UINavigationController对象,并指定该导航控制器对象的根控制器rootViewcontroller。
定制导航栏的显示样式。例如,可以设置导航栏的标题,需要注意的是该属性是在UINavigationController的父类UIViewController类中定义的。

-(instancetype)initWithRootViewController:(UIViewVontroller *)rootViewController;

// 示例
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOption:(NSDictionary *)launchOptions {
    UIViewController *navRootVC = [[UIViewController alloc] init];
    navRootVC,view.backgroundColor = [UIColor redColor];
    UINavigationController *navVC = [[UINavigationController alloc] initWithRootViewController:navRootVC];
    navRoot.title = @"navigation";
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen],bounds];
    self.window.rootViewController = navVC;
    [self.window makeKeyAndVisible];
    return YES;
}

控制器跳转

导航控制器的定义中,提供了Push与Pop的方法,来实现子控制器之间的跳转,其中,Push对应入栈操作,Pop对应出栈操作。
// 入栈操作,显示新的子控制器。
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
// 出栈操作,显示目前在栈顶的控制器。
-(nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;
// 出栈操作,显示指定的控制器。
-(nullable NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
// 出栈操作,显示导航控制器的根控制器。
-(nullable NSArray *)popToRootViewControllerAnimated:(BOOL)animated;

子控制器的管理

1.管理UINavigationController的子控制器
// 获取导航控制器管理的所有子控制器。导航控制器的viewControllers属性是一个数组,有序存放了被该导航控制器管理的所有子控制器。
@property(nonatomic, copy) NSArray *viewController;
// 获取栈顶控制器
@property(nullable, nonatomic, readonly, strong) UIViewController *topViewController;
2.UIViewController中有关导航控制器的属性
@interface UIViewController(UINavigationController)
@property(nullable, nonatomic, readonly, strong) UINavigationController *navigationController;
@end

4 UINavigationBar

UINavigationBar继承自UIView,它是UINavigationController中的一个重要属性,因此,导航栏样式主要(不是全部)是由UINavigationBar决定的,其影响的主要是除导航栏中按钮和标题之外的样式,例如背景颜色、背景图片等,而导航栏中左右两侧的按钮和中间的标题是在子控制器中设置的。这样的实现方式,既可以保证导航栏总体样式的统一(由UINavigationController的UINavigationBar决定),又可以兼顾每个子控制器的功能定制灵活性。

1.UINavigationBar介绍
// UINavigationBar自身的外观属性:如背景颜色,文字颜色、BarStyle、背景图片等,所有子控制器都会使用的公共样式。
@property(nonatomic, readonly) UINavigationBar *navigationBar;
// UINavigationBar上的UINavigationItem:NavigationBar上的按钮都是UINavigationItem对象。
2.UINavigationBar的外观属性
// 导航栏整体样式。
@property(nonatomic, assign) UIBarStyle barStyle;
// 导航栏文字颜色。
@property(null_resettable, nonatomic, strong) UIColor *tintColor;
// 导航栏背景颜色。
@property(nullable, nonatomic, strong) UIColor *barTintColor;
// 设置导航栏背景图片。
-(void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics;
3.获取子控制器的UINavigationItem
@property(nullable, nonatomic, copy) NSArray<UINavigationItem *>items;
@property(nullable, nonatomic, readonly, strong) UINavigationItem *topItem;
@property(nullable, nonatomic, readonly, strong) UINavigationItem *backItem;

5 barStyle属性

UINavigationBar中的barStyle属性用于定制导航栏的样式,其有两种取值,分别是默认(UIBarStyleDefault)和黑色(UIBarStyleBlack)

@property(nonatomic, assign) UIBarStyle barStyle;
typedef NS_ENUM(NSInteger, UIBarStyle) {
    UIBarStyleDefault  = 0,
    UIBarStyleBlack    = 1,
}

// 示例
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    UIViewController *navRootVC = [[UIViewController alloc] init];
    navRootVC.view.backgroundColor = [UIColor whiteColor];
    UINavigationController navVC = [[UINavigationController alloc] initWithRootCiewController:navRootVC];
    navVC.navigationBar.barStyle = UIBarStyleBlack;

    nacRootVC.title = @"";
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = navVC;
    [self.window.makeKeyAndVisible];
    return YES;
}

6 barTintColor与tintColor

barTintColor属性用于设置导航栏背景颜色,通过修改该属性,可以设置导航栏的整体背景颜色。虽然UINavigationBar继承自UIView,但是设置导航栏的背景颜色并不是使用backgroundColor属性,而是barTintColor属性。

@property(nullable, nonatomic, strong) UIColor* barTintColor;

// 示例
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // ...
    navVC.navigationBar.barTintColor = [UIColor greenColor];
    // ...
    return YES;
}
// tintColor属性用于设置导航栏图标被渲染的颜色。
@property(null_resettable, nonatomic, strong) UIColor *tintColor;

7 导航栏设置背景图片

默认情况下,导航栏使用的是近似于白色的纯色背景,也可以为导航栏添加一个整体的背景图片。在UINavigationBar类中,提供了setBackgroundImag:forBarMetrics:方法,该方法可以为导航栏添加背景图片。

-(void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics;

// 示例
[navVC.navigationBar setBackgroundImae:[UIImage imageNamed:@"bkg_image"] forBarMetrics:UIBarMetricsDefault];

8 UINavigationItem

UINavigationItem类的对象包含了用于设置导航栏的左侧、右侧以及中间视图的属性。其中:中间可以显示一个UIView类型的titleView,左右两侧可以分别显示一个或者多个按钮。需要注意的是,显示在导航栏两侧的按钮是UIBarButtonItem类的对象,不是UIButton类。

1.UINavigationItem的常用属性
// 中间的标题视图。
@property(nullable, noatomic, strong) UIView *titleView;
// 左侧/右侧单个按钮。
@property(nullable, noatomic, strong) UIBarButtonItem *leftBarButtonItem;
@property(nullable, noatomic, strong) UIBarButtonItem *rightBarButtonItem;
// 左侧/右侧设置多个按钮。当需要在导航栏两侧设置多个按钮时,可以创建若干个UIBarButtonItem对象,然后把这些对象放到leftBarButtonItems或rightBarButtonItems数组中。
@property(nullable, noatomic, copy) NSArray<UIBarButtonItem *> *leftBarButtonItem;
@property(nullable, noatomic, copy) NSArray<UIBarButtonItem *> *rightBarButtonItem;
// 标题,如果设置了该属性,titleView不生效。UIViewController类也有一个title属性可以用于设置导航栏的标题,但UINavigationItem的title优先级要高。
@property(nullable, noatomic, copy) NSString *title;
// 导航栏提示语。
@property(nullable, noatomic, copy) NSString *prompt;
2.UINavigationItem对象的创建
// 在UINavigationItem类的API中提供了initWithTitle:方法用于UINavigationItem对象的创建。
// 使用该方法创建的UINavigationItem对象只有中间的标题,左右两侧的按钮(UIBarButtonItem类)需要另外定制。
-(instancetype)initWithTitle:(NSString *)title;
3.UIBarButtonItem类
// UINavigationItem类中定义的按钮,不是UIButton类的,而是UIBarButtonItem类的,并且从UIBarButtonItem类的继承关系来看,其父类并不是UIView,而是UIBarItem,因此,UIBarButtonItem类并不具备诸如:backgroundColor之类的属性
// 在UIBarButtonItem类的定义中,也提供了几种常用的实例化方法,比较常用的有以下两个。
// 实例化一个只显示文字的按钮。
-(instancetype)initWithTitle:(nullable NSString *)title style:(UIBarButtonItemStyle)style target:(nullable id)target action:(nullable SEL)action;
// 实例化一个只有图标的按钮。
-(instancetype)initWithImage:(nullable UIImage *)image style:(UIBarButtonItemStyle)style target:(nullable id)target action:(nullable SEL)action;
// 当需要定制UIBarButtonItem类的外观时,可以使用initWithCustomView:方法,该方法传入一个UIView的参数,可以显示定制样式。
-(instancetype)initWithCustomView:(UIView *)customView;

10 UINavigationItem显示原始图片样式

在UIBarButtonItem的初始化方法中,提供了initWithCustomView:方法,该方法需要传入一个UIView的对象,因此,可以考虑传入一个UIButton对象,把原始图片设置为该UIButton的图片。

-(instacnetype)initWithCustumView:(UIView *)customView;

// 
UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
rightBtn.frame = CGRectMake(0, 0, 40, 40);
[rightBtn setIamge:[UIImage imageNamed:@"iamge"] forState:UIControlStateNormal];
[rightBtn addTarget:self action:@selector(clickRightBarButton) forControlEvents:UIControlEventTouchUpInside];
//
UIBarButtonItem *rightBarButtonItem = [[UIBarButtomItem alloc] initWithCustomView:rightBtn];
navRootVC.navigationItem.rightBarButtomItem = rightBarButtomItem;

11 UINavigationController的代理方法

UINavigationController的代理方法可以监听控制器的入栈和出栈操作,同时UINavigationBar的代理方法可以监听navigationItem的入栈和出栈操作,这两种代理协议需要注意区分.

1.UINavigationControllerDelegate代理协议
UINavigationController的代理方法可以监听控制器的入栈和出栈操作,一般把目标控制器设置为UINavigationController的代理对象。
// 当源控制器执行Push或者Pop操作后,目标控制器即将显示时调用。
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
// 当源控制器执行Push或者Pop操作后,目标控制器已经显示时调用。
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
2.UINavigationBarDelegate代理协议
UINavigationBar的代理方法可以监听UINavigationBar添加NavigationItem的入栈和出栈操作,一般把导航控制器设置为UINavigationBar的代理对象。
// 是否允许调用入栈push方法。
-(BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPushItem:(UINavigationItem *)item;
// 是否允许调用出栈pop方法。
-(BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
// 入栈push动画播放完成后调用。
-(void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item;
// 出栈pop动画播放完成后调用。
-(void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item;

12 顺传数据

在导航控制器管理的子控制器之间传递数据的过程中,有以下几个概念需要首先明确一下。

源控制器:调用pushViewController:方法的控制器。
目标控制器:调用pushViewController:方法后,展示出来的新控制器。
顺传:源控制器向目标控制器传递数据。
逆传:目标控制器向源控制器传递数据。

顺传数据的核心思路是在目标控制中新增一个数据模型的属性,在执行pushViewController:方法之前,把源控制器中的数据传递给该属性。一般情况下包括如下两个步骤。

在目标控制(DestinationViewController.h)中新增属性,用于接收数据。
在源控制器(SourceViewController.m)中初始化目标控制器,给目标控制器的新增属性赋值,并跳转到目标控制器。

@

13 使用代理逆传数据

在DestinationViewController.h中,新增代理协议DestinationViewControllerDelegate,并添加一个用于回传数据的代理方法。

在DestinationViewController.h中,新增代理属性。

在目标控制器中,需要执行popViewController:方法之前,通知代理对象调用代理协议中定义的方法。例如,当点击屏幕时返回源控制器,在返回源控制器之前,调用代理方法,并且传递一个字符串参数(数据)给源控制器。

设置SourceViewController类遵守DestinationViewControllerDelegate代理协议。

设置目标控制器的代理对象。在SourceViewController.m中,在实例化目标控制器后,设置其代理对象为源控制器。

在SourceViewController.m中,在代理方法中实现具体功能.

14 使用通知逆传数据

与代理相比,通知的优点在于可以支持一对多的进行数据传递。使用通知进行数据逆向传递,可以按照如下步骤进行编码。

在源控制器SourceViewController.m中,注册观察者。

在源控制器SourceViewController.m中,实现收到通知后的操作,即实现receiveMessage:方法。从目标控制器中传递的通知中,携带了传递过来的数据对象。

不要忘记在源控制器SourceViewController.m中,在dealloc方法中移除观察者。

在目标控制器DestinationViewController.m中,在目标控制器出栈前(调用popViewControllerAnimated:方法前),推送通知给各个观察者,在推送的通知中传递需要交互的数据对象。

15 使Block逆传数据

在目标控制器DestinationViewController.h中,添加Block属性。

在目标控制器DestinationViewController.m中,设置Block中代码的执行时机,即在返回上一个控制器之前调用。

在源控制器SourceViewController.m中,给目标控制器对象的Block赋值,即调用Block时需要执行的操作。

16 工具栏toolBar

1.toolBar属于UIToolbar类,在UIToolbar类中,常用的属性和方法有以下几个。
// barStyle:toolBar的样式,默认情况下是如图9-43所示的蓝色主色样式。
@property(nonatomic) UIBarStyle barStyle;
// items:存放toolBar上的UIBarButtonItem类按钮对象。
@property(nullable, nonatomic, copy) NSArray *items;
// barTintColor:toolBar背景颜色。
@property(nullable, nonatomic, strong) UIColor *barTintColot;
// tintColor:toolBar控件渲染的颜色。
@property(null_resettable, nonatomic, strong) UIColor *tintColor;
// 设置toolBar的背景图片。
-(void)setBackgroundImage:(nullable UIImage *)backgroundImage forToolbarPosition:(UIBarPosition)topOrBottom barMetrics:(UIBarMetrics)barMetrics;
2.导航控制器中的toolBar
// toolBar对象,只读属性,因此不能修改该属性的值。
@property(null_resettable, nonatomic, readonly) UIToolbar *toolBarl
// toolBar的隐藏与显示,默认情况下是隐藏的。
@property(nonatomic, getter-isToolbarHidden) BOOL toolbarHidden;
// 导航控制器使用自定义toolBar。
-(instancetype)initWithNavigationBarClass:(nullable Class)navigationBarClass toolbarClass:(nullable Class)toolbarClass;
3.视图控制器中的toolbarItems
@interface UIViewController (UINavigationControllerContextualToolbarItems)
@property(nullable, nonatomic, strong) NSArray *toolbarItems;
@end

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值