当程序需要显示具有层次化的界面,帮助我们跳转页面的时候,需要使用UINavigationController
1. 通过自定义 NavigationBar 来创建 UINavigationController
- (instancetype)initWithNavigationBarClass:(nullable Class)navigationBarClass toolbarClass:(nullable Class)toolbarClass;
2. 通过设置根控制器创建
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController;
1. 栈顶控制器
@property(nullable, nonatomic,readonly,strong) UIViewController *topViewController;
2. 可见控制器
@property(nullable, nonatomic,readonly,strong) UIViewController *visibleViewController;
3. 栈当中的控制器数组
@property(nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers;
4. 控制器当中的上控制栏
@property(nonatomic,readonly) UINavigationBar *navigationBar;
5. 控制器当中的底栏
@property(null_resettable,nonatomic,readonly) UIToolbar *toolbar;
6. 代理对象
@property(nullable, nonatomic, weak) id delegate;
7. 边缘侧滑返回手势
@property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer;
1. 将参数当中的控制器推入栈中且刷新屏幕。(注意:这个方法不能随便使用,否则编译器运行时报界面找不到。)
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
2. 弹出当前导航控制器栈顶的控制器并且刷新屏幕
- (nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;
3. 弹出所有除根控制器以外在栈当中的控制器并且刷新屏幕
- (nullable NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated;
4. 将栈中的控制器弹出直到指定的控制器位于导航控制器栈的顶端
- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
1. 导航栏标题
@property(nullable, nonatomic, copy) NSString *title;
2. 导航栏左边的项目
@property(nullable, nonatomic, strong) UIBarButtonItem *leftBarButtonItem;
如果需要设置是否点击以后有动画,需要调用 - (void)setLeftBarButtonItem:(nullable UIBarButtonItem *)item animated:(BOOL)animated; 方法
3. 导航栏左边多个项目
@property(nullable,nonatomic,copy) NSArray *leftBarButtonItems;
4. 导航栏右边的项目
@property(nullable, nonatomic, strong) UIBarButtonItem *rightBarButtonItem;
如果需要设置是否点击以后有动画,需要调用 - (void)setRightBarButtonItem:(nullable UIBarButtonItem *)item animated:(BOOL)animated; 方法
5. 导航栏右边多个项目
@property(nullable,nonatomic,copy) NSArray *rightBarButtonItems;
6. 设置除展示返回键以外是否展示其他按钮。The value in the hidesBackButton property still determines whether the back button is actually displayed.
@property(nonatomic) BOOL leftItemsSupplementBackButton
注意:在设置UIBarButtonItem的时候,不能设置重复的选项,否则会出现显示不正常
1. 当程序启动的时候,会先进入导航控制器的根控制器。这个时候导航控制器当中的控制器栈就会将根控制器压入进去。
2. 每当程序进入一个新的控制器的时候,新控制器就会被压入导航控制器的控制器栈当中。导航控制器栈中元素 +1。
3. 当程序退出当前控制器以后,会将之前的控制器弹出导航控制器栈当中。导航控制器栈中元素 -1。
4. 如果你需要返回的控制器不是直接相关的控制器,则栈会将这里面的在需要弹出来之前的所有控制器全部都弹出来。
1. 当往其他控制器传的值是为了设置导航栏或者是底栏的数据的时候,直接传值即可。
2. 当往其他控制器上的控件传值的时候,需要先将值存储在控制器当中的自定义属性上,然后再从 viewDidLoad 方法当中设置(保证控制器的 view 加载完成。因为控制器当中的控件均为懒加载的,只有界面完全加载完成才是创建成功)。
3. 当通过 StoryBoard 传值的时候,需要在目标控制器当中重写 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender; 通过这个方法,可以将上个控制器当中的数据,传递给下一个控制器。
在这种结构下,UITabBarController 作为最底层的控制器。负责控制 4 个 UINavigationController 的切换。当点击下面的选项的时候,就进入到其中一个 UINavigationController 的 rootViewController。这个是 Apple 推荐的布局方式,因为这样可以保证界面显示和功能的快速切换。
而在这种结构下,UINavigationController 作为最底层的控制器,他的根控制器为 UITabBarController。UITabBarController 管理着其他控制器的切换,当在 UITabBar 当中选中一个控制器,控制器当中点击一个按钮进入新控制器的时候,下面的 UITabBar 就会一起同时被移动走。现在常用的社交类 App 都是用这种控制器管理模式。
参考链接:UINavigationController使用心得 - 简书
参考图片:https://github.com/geektime-geekbang/geektime-ios-course/blob/master/Doc/极客时间《从0开发一款iOS应用》课件.pdf