iOS--UINavigationController学习笔记

本文介绍了UINavigationController的原理和使用,包括其管理的视图控制器栈、导航栏的属性和方法,如pushViewController和popViewControllerAnimated。此外,还讨论了UINavigationBar的属性设置,如barTintColor、tintColor和titleTextAttributes,以及UINavigationItem在导航栏中的作用。最后,讲解了如何定制导航栏的内容,如title和left/rightBarButtonItem。
摘要由CSDN通过智能技术生成
1.简介
        UINavigationController:是iOS常见的一种容器型Controller。官方文档上给出的注释如下
 UINavigationController manages a stack of view controllers and a navigation bar. It performs horizontal view transitions for pushed and popped views while keeping the navigation bar in sync. Most clients will not need to subclass UINavigationController. If a navigation controller is nested in a tabbar controller, it uses the title and toolbar attributes of the bottom view controller on the stack. UINavigationController is rotatable if its top view controller is rotatable. Navigation between controllers with non-uniform rotatability is currently not supported.
意思是说,UINavigationController管理着一个viewController的栈和一个navigation bar(navigation bar后面会说)。管理着出于同一层次的viewController的view,包括压栈和出栈(viewController显示滑进和隐藏滑出界)的转场动画,同时还同步管理着顶部navigation bar的状态。大部分的app都不需要实现一个它的子类(对于一般的功能,都具有支持)。如果一个UINavigationController的实例嵌套在一个UITabbarController的实例中,它将使用栈底的viewController的标题和toolbar的属性。UINavigationController的可旋转是和栈顶的viewController保持一致的。现在还不支持同一层次的viewController旋转类型不一致的压栈出栈。

2.常见属性和方法
- ( instancetype )initWithRootViewController:(UIViewController *)rootViewController; 
以一个viewController为栈底,实例化一个navigation viewcontroller

- ( void )pushViewController:(UIViewController *)viewController animated:( BOOL )animated; 
展示一个viewcontroller,压栈操作(可以有动画效果)。

- ( nullable UIViewController *)popViewControllerAnimated:( BOOL )animated; 
结束并隐藏一个viewcontroller(dealloc),出栈操作(可以有动画效果),返回出栈的viewcontroller

- ( nullable NSArray< __kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:( BOOL )animated; 
结束并隐藏 在栈中位于一个特殊的viewcontroller之前所有的viewcontroller,并返回

- ( nullable NSArray< __kindof UIViewController *> *)popToRootViewControllerAnimated:( BOOL )animated;
出栈到根viewcontroller

@property ( nullable , nonatomic , readonly , strong ) UIViewController *topViewController; 
栈顶viewcontroller

@property ( nullable , nonatomic , readonly , strong ) UIViewController *visibleViewController; 
如果模态viewcontroller存在,返回 模态viewcontroller,否则 栈顶viewcontroller

@property ( nonatomic , copy ) NSArray< __kindof UIViewController *> *viewControllers; 
当前栈中的元素

- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated NS_AVAILABLE_IOS(3_0); 
设置栈中的元素, animated=yes,根据当前的栈顶viewcontroller在不在这个viewcontroller数组中,模拟一次push和pop的动画。这就相当于对当前的栈进行了一次整体的刷新

下面的bar属性主要是用来显示顶部的导航栏以及底部的工具栏
@property ( nonatomic , getter =isNavigationBarHidden) BOOL navigationBarHidden;
- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated; 
@property ( nonatomic , readonly ) UINavigationBar *navigationBar; 
@property ( nonatomic , getter =isToolbarHidden) BOOL toolbarHidden NS_AVAILABLE_IOS( 3 _0) __TVOS_PROHIBITED;
- (void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED; 
@property ( null_resettable , nonatomic , readonly ) UIToolbar *toolbar NS_AVAILABLE_IOS( 3 _0) __TVOS_PROHIBITED; // 

delegate,可以在压栈出栈操作中,设置一些动画,以及一些额外的操作
@property ( nullable , nonatomic , weak ) id <UINavigationControllerDelegate> delegate;

这里需要说一下visibleViewController和topViewController:topViewController永远代表着栈顶元素;visibleViewController代表着当前显示的那个vc,这个vc可能是top vc,也有可能是top vc 展示出来的vc。

3.UINavigationBar

3.1. 导航栏属性设置:

       通常我们都会在APPDelegate为整个APP的导航栏做全局性的设置,使用 [ UINavigationBar appearance ]这个方法获得当前的导航栏实例;以及在viewController中对当前页面的导航栏做特殊的设置,使用 self.navigationController.navigationBar 获得当前的导航栏实例。记住,在viewController中对导航栏的设置,要在这个viewController小时之前还原,否则会覆盖全局的设置,从而影响其他页面的显示。
      barTintColor:设置导航栏的整体背景颜色,包括状态栏的背景颜色。如下:
 [ [ UINavigationBar appearance ] setBarTintColor :[ UIColor yellowColor ]];运行的效果如下
                   
                   
      tintColor:设置导航栏的按钮的图标和文字颜色(系统提供的),自定义的不在此范围;
 [[ UINavigationBar appearance ] setTintColor :[ UIColor redColor ]];运行的效果如下
                   
      barStyle:设置导航栏的整体风格,有UIBarStyleDefault和UIBarStyleBlack两种选择。对应以下两种运行结果,可以看到UIBarStyleBlack会影响状态栏的颜色以及导航栏的标题颜色。(但是已经对标题的字体颜色都已经赋值的,就不受影响了)
                    
                   
     titleTextAttributes:设置导航栏的标题的显示样式,包括 UITextAttributeFont - 字体  UITextAttributeTextColor - 文字颜色   UITextAttributeTextShadowColor - 文字阴影颜色     UITextAttributeTextShadowOffset - 偏移用于文本阴影
       [[ UINavigationBar appearance ] setTitleTextAttributes :[ NSDictionary dictionaryWithObjectsAndKeys :
                                                   [UIColor redColor ], NSForegroundColorAttributeName ,
                                                   [ UIFont systemFontOfSize : 18.f ], NSFontAttributeName ,
                                                  nil]];
                   
     backgroundImage/shadowImage:设置导航栏的背景和阴影图片
    [ [ UINavigationBar appearance ] setBackgroundImage:[UIImageimageNamed:xxx]
                             forBarMetrics : UIBarMetricsDefault ];
    [ [ UINavigationBar appearance ] setShadowImage:[UIImageimageNamed:xxx]];
      translucent:BOOL,半透明效果。

        补充点:前面说到也可以在viewController中对UINavigationBar进行属性设置,基本上都会生效。但是,有些情况下会发现,viewController的 (UIStatusBarStyle)preferredStatusBarStyle是不起作用的,原因是因为当前的viewController是嵌套在一个UINavigationController的实例中,最多只会调用UINavigationController的 preferredStatusBarStyle,除非将导航栏隐藏,才会调用 viewController的 preferredStatusBarStyle方法。解决办法:在iOS9之前, App的info.plist文件中,添加 View controller-based status bar appearance的值为NO,(意识是说让Application的设置优先于viewController的设置),通过 [[UIApplication sharedApplication] setStatusBarStyle:]这个方法来进行设置修改statusBar;但是在iOS9之后,该方法会提示过时⚠️,解决办法是将  View controller-based status bar appearance的值设置YES,然后通过navigationBar.barStyle来设置。然而,现在很多应用都是在iOS7做适配的时候,将 View controller-based status bar appearance设为NO,(iOS之前,默认值为NO,iOS之后为YES),iOS7和8对此也都处于兼容状态。9之后会出现警告。

3.2. UINavigationItem以及其与UINavigationBar的关系:

      在前面的简介之中,提到UINavigationController管理着一个UIViewController的栈和一个UINavigationBar。其实,一个UINavigationController的实例对应一个UINavigationBar的实例,而一个UINavigationBar的实例同样管理着一个栈,这个栈中的元素就是UINavigationItem。所以,既然一个navigationController对应一个navigationBar,可以推断到UINavigationController的栈和UINavigationBar的栈也是对应的,而两个栈里元素也是一一对应,也就是一个UIViewController的实例也对应着一个UINavigationItem的实例(如果不对应,系统会报异常情况)。在navigationController进行push和pop的同时,navigationBar也在同时做相应的push和pop 。在官方的API中,在UINavigationController.h文件中会有一个UIViewController的一个category,里面定义着一个UINavigationItem的变量。
    

3.3.  定制导航栏内容
     
       定制导航栏一般都是在viewController中进行自我定制navigationItem。
       定制title,使用viewController.title和viewController.navigationItem.title都可以实现导航栏title的定制。补充:设置viewController.title会覆盖viewController.navigationItem.title,设置viewController.navigationItem.title不会覆盖viewController.title。
       有的时候需要将导航栏标题修改为一个我们自己想要的UIView,只要将我们需要的UIView赋值给viewController.navigationItem.titleView。比如一个button,一张图片,一个搜索框等等
       定制left/rightBarButtonItem:在导航栏中,左右两边通常都会有一些button或者需要交互的view。这时候就需要给viewController.navigationItem设置left/rightBarButtonItem,可定制成任意样式。
       在导航栏中,如果本身没有对viewController.navigationItem.leftBarButtonItem进行定制,会优先展示上一个页面的backBarButtonItem;如果上一个页面也没有设置backBarButtonItem,就会展示一个系统的回退按钮和上一个页面的title。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值