UINavigationController

UINavigationController

  • 导航控制器是一个堆栈结构,只是其中管理的对象是controller,通过push与pop进行controller的切换,我们有两种方式可以创建导航控制器:
//通过一个自定义的导航栏和工具栏创建导航控制器

- (instancetype)initWithNavigationBarClass:(nullable Class)navigationBarClass toolbarClass:(nullable Class)toolbarClass;

//使用系统默认的导航栏和工具栏,通过一个根视图创建导航控制器

- (instancetype)initWithRootViewController:(UIViewController *)rootViewController;
  • 通过以下方法对视图控制器进行管理操作:
//设置管理的视图控制器

- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated;

//压入新的视图控制器

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;

//弹出一个视图控制器 返回的是pop的controller

- (nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;

//弹出到某个视图控制器 返回所有pop的controller

- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated; 

//直接pop到根视图控制器,返回所有被pop的controller

- (nullable NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated;
//返回栈顶的controller
@property(nullable, nonatomic,readonly,strong) UIViewController *topViewController; 

//返回显示的controller
@property(nullable, nonatomic,readonly,strong) UIViewController *visibleViewController;

> 上面两个方法的区别在于,topViewController是返回被push出的最后一个controller,但是如果之后又有present进行模态跳转,visibleViewController会返回当前显示的controller。例如A-push-B-present-C,则topViewController会返回B,visibleViewController会返回C。
//返回堆栈中所有的controller
@property(nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers;
//设置隐藏导航栏
@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);
- (void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated;
//状态栏对象
@property(null_resettable,nonatomic,readonly) UIToolbar *toolbar;
//导航中的返回手势对象
//iOS7之后,在导航中右划会进行pop操作,设置这个的enable可以控制设置手势是否失效
@property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer;
//这个方法是为了iOS方法的命名统一,在导航中,其作用和push一样
- (void)showViewController:(UIViewController *)vc sender:(nullable id)sender;

//屏幕滑动的时候隐藏导航栏,常用于tableView,上滑隐藏导航栏,下滑显示,带动画效果
@property (nonatomic, readwrite, assign) BOOL hidesBarsOnSwipe;
//敲击屏幕可以隐藏与显示导航栏
@property (nonatomic, readwrite, assign) BOOL hidesBarsOnTap;

//横屏的时候隐藏导航栏
@property (nonatomic, readwrite, assign) BOOL hidesBarsWhenVerticallyCompact;
//弹出键盘的时候隐藏导航栏
@property (nonatomic, readwrite, assign) BOOL hidesBarsWhenKeyboardAppears;

//获取敲击屏幕的手势
@property (nonatomic, readonly, assign) UITapGestureRecognizer *barHideOnTapGestureRecognizer;
//获取滑动隐藏导航栏的手势
@property (nonatomic, readonly, strong) UIPanGestureRecognizer *barHideOnSwipeGestureRecognizer;
  • Delegate
//视图将要展示时调用的方法

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

//视图已经展示时调用的方法

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

//设置方法设置导航控制器支持的设备方向

-(UIInterfaceOrientationMask)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController NS_AVAILABLE_IOS(7_0);

//这个方法设置导航控制器的首选设备方向

-(UIInterfaceOrientation)navigationControllerPreferredInterfaceOrientationForPresentation:(UINavigationController *)navigationController NS_AVAILABLE_IOS(7_0);

//下面两个方法可以对导航的转场动画进行设置

-(nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController;

-(nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
  • 当一个controller被添加到导航中后,系统会为它分配一些属性,如下:
//当前controller对应的导航项
@property(nonatomic,readonly,strong) UINavigationItem *navigationItem;

//push的时候隐藏底部栏,如push后隐藏tabbar
@property(nonatomic) BOOL hidesBottomBarWhenPushed;

//管理它的导航控制器
@property(nullable, nonatomic,readonly,strong) UINavigationController *navigationController;

UINavigtionBar

可以在不使用导航控制器的前提下,单独使用导航栏.

导航栏继承于UIView,所以我们可以像创建普通视图那样创建导航栏,比如我们创建一个高度为80的导航栏,将其放在ViewController的头部,代码如下:

UINavigationBar *bar = [[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 80)];
[self.view addSubview:bar];

也可以设置导航栏的风格属性,从iOS6之后,UINavigationBar默认为半透明的样式,从上面也可以看出,白色的导航栏下面透出些许背景的红色。导航栏的风格属性可以通过下面的属性来设置:

@property(nonatomic,assign) UIBarStyle barStyle;

UIBarStyle是一个枚举,其中大部分的样式都已弃用,有效果的只有如下两个:

typedef NS_ENUM(NSInteger, UIBarStyle) {
UIBarStyleDefault          = 0,//默认
UIBarStyleBlack            = 1,//黑色
}

从上面我们可以看到,iOS6后导航栏默认都是半透明的,我们可以通过下面的bool值来设置这个属性,设置为NO,则导航栏不透明,默认为YES:

@property(nonatomic,assign,getter=isTranslucent) BOOL translucent;

下面一些方法用于设置NavigationBar及上面item的颜色相关属性:

tintColor这个属性会影响到导航栏上左侧pop按钮的图案颜色和字体颜色,系统默认是蓝色

@property(null_resettable, nonatomic,strong) UIColor *tintColor;

BarTintColor用于设置导航栏的背景色,这个属性被设置后,半透明的效果将失效:

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

两个方法用于设置和获取导航栏的背景图案

- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;
- (nullable UIImage *)backgroundImageForBarMetrics:(UIBarMetrics)barMetrics;

这里需要注意,默认背景图案是不做缩放处理的,所以我们使用的图片尺寸要和导航栏尺寸匹配,这里面还有一个UIBarMetrics参数,这个参数设置设备的状态,如下:

typedef NS_ENUM(NSInteger, UIBarMetrics) {
    UIBarMetricsDefault,//正常竖屏状态
    UIBarMetricsCompact,//横屏状态
};
//设置导航栏的阴影图片
@property(nullable, nonatomic,strong) UIImage *shadowImage;
//设置导航栏的标题字体属性
@property(nullable,nonatomic,copy) NSDictionary<NSString *,id> *titleTextAttributes;

标题字体属性会影响到导航栏的中间标题,如下:

bar.titleTextAttributes = @{NSForegroundColorAttributeName:[UIColor redColor]};

我们也可以通过下面的属性设置导航栏标题的竖直位置偏移:

- (void)setTitleVerticalPositionAdjustment:(CGFloat)adjustment forBarMetrics:(UIBarMetrics)barMetrics;

- (CGFloat)titleVerticalPositionAdjustmentForBarMetrics:(UIBarMetrics)barMetrics;

还有一个细节,导航栏左侧pop按钮的图案默认是一个箭头,我们可以使用下面的方法修改:

@property(nullable,nonatomic,strong) UIImage *backIndicatorImage;
@property(nullable,nonatomic,strong) UIImage *backIndicatorTransitionMaskImage;
  • 导航栏中item的push与pop操作

UINavigationBar上面不只是简单的显示标题,它也将标题进行了堆栈的管理,每一个标题抽象为的对象在iOS系统中是UINavigationItem对象,我们可以通过push与pop操作管理item组。

//向栈中添加一个item,上一个item会被推向导航栏的左侧,变为pop按钮,会有一个动画效果
- (void)pushNavigationItem:(UINavigationItem *)item animated:(BOOL)animated;
//pop一个item
- (nullable UINavigationItem *)popNavigationItemAnimated:(BOOL)animated; 
//当前push到最上层的item
@property(nullable, nonatomic,readonly,strong) UINavigationItem *topItem;
//仅次于最上层的item,一般式被推向导航栏左侧的item
@property(nullable, nonatomic,readonly,strong) UINavigationItem *backItem;
//获取堆栈中所有item的数组
@property(nullable,nonatomic,copy) NSArray<UINavigationItem *> *items;
//设置一组item
- (void)setItems:(nullable NSArray<UINavigationItem *> *)items animated:(BOOL)animated;
  • UINavigationBarDelegate

在UINavigationBar中,还有如下一个属性:

@property(nullable,nonatomic,weak) id<UINavigationBarDelegate> delegate;

通过代理,我们可以监控导航栏的一些push与pop操作:

//item将要push的时候调用,返回NO,则不能push
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPushItem:(UINavigationItem *)item; 
//item已经push后调用
- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item; 
//item将要pop时调用,返回NO,不能pop  
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item; 
//item已经pop后调用 
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item;

UINavigationItem

Item,从英文上来理解,它可以解释为一个项目,因此,item不是一个简单的label标题,也不是一个简单的button按钮,它是导航栏中管理的一个项目的抽象。说起来有些难于理解,通过代码,我们就能很好的理解Item的意义。

首先,我们创建一个item,用UINavigationBar导航栏push出来:

 UINavigationItem * item = [[UINavigationItem alloc]initWithTitle:@"title"];
 UINavigationBar * bar = [[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 64)];
 [bar pushNavigationItem:item animated:YES];

除了创建一个标题item,我们也可以创建一个View类型的item:

 UIView * view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 30, 30)];
        view.backgroundColor = [UIColor brownColor];
        item.titleView = view;

通过下面的属性,可以给这个Item添加一个说明文字,这段文字会显示在item的上方:

item.prompt= @"我是navigationItem的说明文字";

上面我们看到的这些,实际上只是一个item的一部分,item还有许多其他的附件,如果我们使导航栏再push出一个item,这时导航栏的左边会出现一个返回按钮,这个返回按钮实际上是数据第一个item的,我们做如下的设置:

UINavigationItem * item = [[UINavigationItem alloc]initWithTitle:@"title"];
        UINavigationItem * item2 = [[UINavigationItem alloc]initWithTitle:@"title2"];
        item.backBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"title1" style:nil target:nil action:nil];
        [bar pushNavigationItem:item animated:YES];
        [bar pushNavigationItem:item2 animated:YES];

上面我们看到的这些,实际上只是一个item的一部分,item还有许多其他的附件,如果我们使导航栏再push出一个item,这时导航栏的左边会出现一个返回按钮,这个返回按钮实际上是数据第一个item的,我们做如下的设置:

UINavigationItem * item = [[UINavigationItem alloc]initWithTitle:@"title"];
        UINavigationItem * item2 = [[UINavigationItem alloc]initWithTitle:@"title2"];
        item.backBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"title1" style:nil target:nil action:nil];
        [bar pushNavigationItem:item animated:YES];
        [bar pushNavigationItem:item2 animated:YES];

可以看出,虽然当前push出来的item是item2,但是左边的返回按钮是属于item的。这里有一点需要注意,虽然backBarButtonItem的标题我们可以自定义,但是方法和其他属性我们都不能定制,是系统实现好的。

当然,我们也可以设置在push出来新的item的时候,隐藏前面的返回按钮,使用如下属性:

@property(nonatomic,assign) BOOL hidesBackButton;
- (void)setHidesBackButton:(BOOL)hidesBackButton animated:(BOOL)animated;

默认为NO,设置为YES将会隐藏返回按钮。

一个UINavigationItem中,还可以包含许多BarButtonItem,BarButtonItem是一系列的按钮,会出现在导航栏的左侧或者右侧。例如:

 UIBarButtonItem * button = [[UIBarButtonItem alloc]initWithTitle:@"按钮" style:UIBarButtonItemStyleDone target:self action:@selector(click)];
        item.leftBarButtonItem = button;

这个barButtonItem是一个按钮,可以触发一个方法,这有时候对我们来说十分有用。但是有一个你一定发现了,如果继续push出来Item,原来的返回按钮不见了,是否隐藏返回按钮,由下面这个属性控制:

item.leftItemsSupplementBackButton=YES;//YES为显示

我们也可以通过下面的方法设置右边的按钮,或者直接设置一组按钮:

@property(nullable, nonatomic,strong) UIBarButtonItem *leftBarButtonItem;
@property(nullable, nonatomic,strong) UIBarButtonItem *rightBarButtonItem;
- (void)setLeftBarButtonItem:(nullable UIBarButtonItem *)item animated:(BOOL)animated;
- (void)setRightBarButtonItem:(nullable UIBarButtonItem *)item animated:(BOOL)animated;

@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *leftBarButtonItems;
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *rightBarButtonItems;
- (void)setLeftBarButtonItems:(nullable NSArray<UIBarButtonItem *> *)items animated:(BOOL)animated;
- (void)setRightBarButtonItems:(nullable NSArray<UIBarButtonItem *> *)items animated:(BOOL)animated;

一个NavigationItem基本上是有三大部分组成的,当前显示的部分,返回按钮部分,和ButtonItem部分,同样对于创建和设置UIBarButoonItem,也有很多方法供我们使用。

- (instancetype)initWithTitle:(nullable NSString *)title style:(UIBarButtonItemStyle)style target:(nullable id)target action:(nullable SEL)action;

这个方法通过一个标题创建ButtonItem,其中style参数可以设置一个风格,枚举如下:

typedef NS_ENUM(NSInteger, UIBarButtonItemStyle) {
    UIBarButtonItemStylePlain,
    UIBarButtonItemStyleDone,//这两种风格差别并不大,Done风格的字体加粗一些
};

我们因为可以通过一个图片来创建BarButtonItem:

- (instancetype)initWithImage:(nullable UIImage *)image style:(UIBarButtonItemStyle)style target:(nullable id)target action:(nullable SEL)action;
- (instancetype)initWithImage:(nullable UIImage *)image landscapeImagePhone:(nullable UIImage *)landscapeImagePhone style:(UIBarButtonItemStyle)style target:(nullable id)target action:(nullable SEL)action;

上面这两个方法中,第一个方法与使用文字创建的方法类似,第二个方法多了一个landscapeImagePhone的参数,这个参数可以设置设备横屏时的图片。

我们也可以使用自定义的View来创建BarButtonItem:

- (instancetype)initWithCustomView:(UIView *)customView;

除了上面一些自定义的创建方法外,对于BarButtonItem这个对象,系统也封装好了许多原生的可以供我们使用,创建的时候使用如下方法:

UIBarButtonItem * button = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:nil];

上面的SystemItem是系统为我们做好的许多buttonItem的类型,枚举如下:

typedef NS_ENUM(NSInteger, UIBarButtonSystemItem) {
    UIBarButtonSystemItemDone,//显示完成
    UIBarButtonSystemItemCancel,//显示取消
    UIBarButtonSystemItemEdit,  //显示编辑
    UIBarButtonSystemItemSave, //显示保存 
    UIBarButtonSystemItemAdd,//显示加号
    UIBarButtonSystemItemFlexibleSpace,//什么都不显示,占位一个空间位置
    UIBarButtonSystemItemFixedSpace,//和上一个类似
    UIBarButtonSystemItemCompose,//显示写入按钮
    UIBarButtonSystemItemReply,//显示循环按钮
    UIBarButtonSystemItemAction,//显示活动按钮
    UIBarButtonSystemItemOrganize,//显示组合按钮
    UIBarButtonSystemItemBookmarks,//显示图书按钮
    UIBarButtonSystemItemSearch,//显示查找按钮
    UIBarButtonSystemItemRefresh,//显示刷新按钮
    UIBarButtonSystemItemStop,//显示停止按钮
    UIBarButtonSystemItemCamera,//显示相机按钮
    UIBarButtonSystemItemTrash,//显示移除按钮
    UIBarButtonSystemItemPlay,//显示播放按钮
    UIBarButtonSystemItemPause,//显示暂停按钮
    UIBarButtonSystemItemRewind,//显示退后按钮
    UIBarButtonSystemItemFastForward,//显示前进按钮
    UIBarButtonSystemItemUndo,//显示消除按钮
    UIBarButtonSystemItemRedo ,//显示重做按钮
    UIBarButtonSystemItemPageCurl ,//在tool上有效
};

UIToolBar

工具栏和导航栏十分类似,只是功能更加简单,工具栏中也有UIBarButtonItem按钮.

导航栏一般会出现在视图的头部,与之相对,工具栏一般会出现在视图的的底部,上面可以填充一些按钮,提供给用户一些操作。创建一个工具栏如下:

self.view.backgroundColor = [UIColor grayColor];
    UIToolbar * tool = [[UIToolbar alloc]initWithFrame:CGRectMake(0, self.view.frame.size.height-40, 320, 40)];
    [self.view addSubview:tool];

下面是UIToolBar中的一些方法,其中大部分在UINavigationBar中都有涉及,这里只做简单的介绍:

//工具栏的风格,和导航栏类似,有黑白两种
@property(nonatomic) UIBarStyle barStyle; 
//设置工具栏上按钮数组
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *items; 
//设置工具栏是否透明
@property(nonatomic,assign,getter=isTranslucent) BOOL translucent; 
//设置工具栏按钮
- (void)setItems:(nullable NSArray<UIBarButtonItem *> *)items animated:(BOOL)animated; 
//设置item风格颜色
@property(null_resettable, nonatomic,strong) UIColor *tintColor;
//设置工具栏背景色
@property(nullable, nonatomic,strong) UIColor *barTintColor;
//设置工具栏背景和阴影图案
- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forToolbarPosition:(UIBarPosition)topOrBottom barMetrics:(UIBarMetrics)barMetrics;
- (nullable UIImage *)backgroundImageForToolbarPosition:(UIBarPosition)topOrBottom barMetrics:(UIBarMetrics)barMetrics;
- (void)setShadowImage:(nullable UIImage *)shadowImage forToolbarPosition:(UIBarPosition)topOrBottom;
- (nullable UIImage *)shadowImageForToolbarPosition:(UIBarPosition)topOrBottom;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容