UINavigationBar、UINavigationItem
一、UINavigationBar
1、导航条navigationbar属于导航控制器,一个导航控制器只有一个导航条。
2、在一个导航控制器push新页面和pop页面时,导航条是同一个。
3、在一个视图控制器内改变了导航条的样式,其它控制器的导航条的样式也会改变,也说明了导航条属于导航控制器,而不是每个视图控制器都有一个导航条。
4、导航条的层级结构
navigationbar层级:
image.png
UIBarBackground视图是比UINavigationBar视图要大
主要属性:
1.只读属性Items,backItem,topItem分别表示为数组,上一个控制器,当前控制器(栈顶控制器)
也就是说UINavigationBar维护着每个VC的navigationItem
2.translucent
影响VC.view原点坐标
-
一个controller的view的原点位置受self.navigationController. navigationBar 的 setTranslucent (BOOL) 属性控制,在 iOS7 以后 translucent 属性默认为 YES。
translucent 为YES:原点位置坐标为屏幕左顶端,即屏幕坐标系(0 , 0),含义为毛玻璃、半透明效果。
translucent 为NO:原点位置坐标为导航栏的下边的左顶端,即屏幕坐标系(0 , 64),此时导航栏不透明。
注意,当我们设置navigationBar的背景图片setBackgroundImage(注意是背景图片不是背景颜色)的时候,坐标起点也会变成(0,64),因为当我们设置背景图片的时候,系统会自动修改translucent为NO。 -
其实navController不仅有UINavigationBar属性还有个toolbar属性(默认hiddenYES),toolbar的translucent会影响到VC.view的高度,也就是是否延伸到屏幕底部。
3.tintColor
bar上的文字按钮颜色
4.barTintColor
bar的背景色 ios15之后设置无效
由于ios15新特性(bar的背景默认是透明,滚动后与关联的scrollview相交才显示bar的背景),需要通过UINavigationBarAppearance设置bar的背景,scrollEdgeAppearance控制与视图不相交时bar的样式,默认是透明的;standardAppearance控制与视图相交时bar的样式,
if (@available(iOS 15, *)) {
UINavigationBarAppearance *navBarAppearance = [[UINavigationBarAppearance alloc]init];
navBarAppearance.backgroundImage = whiteBG;
navBarAppearance.shadowImage = whiteBG;
navBarAppearance.titleTextAttributes = @{NSFontAttributeName:[UIFont systemFontOfSize:18]};
//设置相交状态
[UINavigationBar appearance].standardAppearance = navBarAppearance;
//设置不相交状态
[UINavigationBar appearance].scrollEdgeAppearance = navBarAppearance;
}
二、UINavigationItem
UINavigationBar是由UINavigationController管理的,但是它的样式由子控制器的self. navigationItem来设置。
也就是说UINavigationBar是全局设置的一经修改,这个nav内的所有导航条都发生变化,而UINavigationItem是针对每个VC的,是VC的只读属性
所以我们应当通过修改UINavigationItem的属性来自定义每个页面的导航条标题/按钮等控件
主要属性:
titleView
leftBarButtonItem,leftBarButtonItems
rightBarButtonItem,rightBarButtonItems
backBarButtonItem
栗子:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"这是返回" style:UIBarButtonItemStylePlain target:self action:@selector(back)];
三、UIBarButtonItem
UINavigationItem的left/right/back的样式是通过UIBarButtonItem创建,常用初始化方法:
UIBarButtonItem : UIBarItem:NSObject
- (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 API_AVAILABLE(ios(5.0)); // landscapeImagePhone will be used for the bar button image when the bar has Compact or Condensed bar metrics.
- (instancetype)initWithTitle:(nullable NSString *)title style:(UIBarButtonItemStyle)style target:(nullable id)target action:(nullable SEL)action;
- (instancetype)initWithBarButtonSystemItem:(UIBarButtonSystemItem)systemItem target:(nullable id)target action:(nullable SEL)action;
- (instancetype)initWithCustomView:(UIView *)customView;
leftBarButtonItem显示原则:
1.如果当前的视图控制器设置了leftBarButtonItem,则显示当前VC所自带的leftBarButtonItem。
2.如果没有设置leftBarButtonItem,且不是根视图控制器的时候,则显示前一层的backBarButtonItem。如果前一层没有指定backBarButtonItem的话,系统将会根据前一层的title属性自动生成一个back按钮,并显示出来。
3.如果没有设置leftBarButtonItem,且已是根视图控制器的时候,左边不显示任何东西。
理解:backBarButtonItem不是显示在当前VC的,而是其他VC返回此VC时候的返回按钮,如果其他VC设置了left,那么left优先级高于此VC的backBarButtonItem,例如:
设置VC1的backBarButtonItem,从VC1push到VC2,如果VC2没设置leftBarButtonItem,那么VC2的左上角返回按钮就是VC1的backBarButtonItem,否则优先左上角显示VC2的leftBarButtonItem
总结
navigationcontroller直接控制viewcontrollers集合,然后它包含的navigationbar是整个工程的导航栏,bar有一个用来管理navigationItem的栈。@property(nonatomic, copy) NSArray <UINavigationItem *> *items
理清以上三者的关系后,可以单独用导航栏UINavigationBar,(不是采用UINavigationController)
代码方式:
- (void)viewDidLoad{
UINavigationBar *navBar = [[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
//添加NavigationBar到视图上
[self.view addSubview:navBar];
UINavigationItem *navItem = [[UINavigationItem alloc]initWithTitle:@"welcome page"];
UIBarButtonItem *btnlogin = [[UIBarButtonItem alloc]initWithTitle:@"login" style:UIBarButtonItemStyleDone target:self action:@selector(login)];
navItem.leftBarButtonItem = btnlogin;
//把NavigationItem添加到导航栏上(进栈)
[navBar pushNavigationItem:navItem animated:NO];
}
navigationcontroller和navigationbar是一对一的关系,而navigationbar和navigationItem则是一对多的关系。