UI基础 - UINavigationController:UINavigationBar | UIToolBar
■ UINavigationController
1. 导航控制器是专门管理具有层级关系内容的导航,以栈的方式管理所控制的视图控制器:至少要有一个被管理的视图控制器,这个被管理的视图控制器是导航控制器的根视图控制器
注:任何继承于 UIViewController 的控制器(包括多态)都可以作为导航控制器的根控制器
2. UINavigationController 是以栈的方式管理视图的,它所管理的视图被放进一个数组中。以下是通过导航控制器进入、返回视图的原理图
注:当底部视图控制器想要返回某一前面的视图控制器时,一定要从导航控制器中的子视图数组中获取
// 错误做法 SecondViewController *secVC = [SecondViewController new]; [self.navigationController popToViewController:secVC animated:YES]; // 正确打开方式 // 根据子控制器的下标,返回指定页面 [self.navigationController popToViewController:(SecondViewController *)[self.navigationController.viewControllers objectAtIndex:1] animated:YES]; // 返回上一级页面呢 [self.navigationController popViewControllerAnimated:YES]; // 返回起始页面:下标是 0 的页面 [self.navigationController popToRootViewControllerAnimated:YES];
3. UINavigationController 的 view层 包含 3 个子视图:navigationBar、toolbar、contentView ,其中 contentView 不是属性,只是一种指代。我们可以通过遍历 view 的 subViews 来找到它
■ UINavigationBar
1. 导航条自 iOS 7 之后默认是透明的,iOS7 之前默认是不透明的:在透明情况下它会与 contentView 重合一部分区域;在不透明情况下 contentView 则会在它的下⾯
2. UINavigationBar 除了能定义⾃身的样式外,还管理了一组 UINavigationItem,它也是以栈的⽅式管理⼀组 Items,并提供有 push/pop 操作。UINavigationItem 属于 MVC 中的 M,封装了要显⽰在 UINavigationBar 上的数据:title、titleView、leftBarButtonItem 等
3. UINavigationItem 样式
4. 如何使用 UINavigationBar
// - AppDelegate.m
1 #import "AppDelegate.h" 2 #import "ViewController.h" 3 @implementation AppDelegate 4 5 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 6 7 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 8 self.window.backgroundColor = [UIColor whiteColor]; 9 [self.window makeKeyAndVisible]; 10 11 ViewController *firstVC =[[ViewController alloc] init]; 12 firstVC.view.backgroundColor = [UIColor yellowColor]; 13 firstVC.title = @"UINavigationController"; 14 UINavigationController *rootVC = [[UINavigationController alloc] initWithRootViewController:firstVC]; 15 // 毛玻璃效果:默认 YES 16 rootVC.navigationBar.translucent = NO; 17 rootVC.navigationBar.hidden = NO; 18 19 20 // 标题颜色、大小:如果设置背景图的话,会覆盖该效果 21 [rootVC.navigationBar setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys: 22 [UIColor yellowColor], 23 NSForegroundColorAttributeName, 24 [UIFont systemFontOfSize:18], 25 NSFontAttributeName,nil]]; 26 27 // iOS 13 之后,需使用 UINavigationBarAppearance 28 if(@available(iOS 13.0,*)){ 29 30 UINavigationBarAppearance *navBarAppearance = [[UINavigationBarAppearance alloc] init]; 31 [navBarAppearance configureWithOpaqueBackground]; 32 // 背景颜色 33 navBarAppearance.backgroundColor = [UIColor redColor]; 34 // 背景图片:图片尺寸和 navigationBar尺寸 不相同的话,会自动填充 35 navBarAppearance.backgroundImage = [UIImage imageNamed:@"P150x20.png"]; 36 navBarAppearance.backgroundImage = [UIImage imageNamed:@"P375x64.png"]; 37 38 // 重设标题颜色、大小 39 [navBarAppearance setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys: 40 [UIColor greenColor], 41 NSForegroundColorAttributeName, 42 [UIFont systemFontOfSize:25], 43 NSFontAttributeName,nil]]; 44 45 rootVC.navigationBar.standardAppearance = navBarAppearance; 46 rootVC.navigationBar.scrollEdgeAppearance = navBarAppearance; 47 48 } 49 // iOS 13 之前配置背景颜色、背景图片 50 else{ 51 // 背景颜色 52 rootVC.navigationBar.barTintColor = [UIColor redColor]; 53 // 背景图片:不会自动填充 54 // 状况一:不同 navigationBar系统尺寸 保持一致的图片,效果展示会存在问题 55 [rootVC.navigationBar setBackgroundImage:[UIImage imageNamed:@"P150x20.png"] forBarMetrics:UIBarMetricsDefault]; 56 // 状况二:同 navigationBar系统尺寸 保持一致的图片,效果展示不存在问题 57 [rootVC.navigationBar setBackgroundImage:[UIImage imageNamed:@"P414x44.png"] forBarMetrics:UIBarMetricsDefault]; 58 } 59 60 self.window.rootViewController = rootVC; 61 return YES; 62 } 63 64 @end
运行效果
■ UIToolBar
1. UIToolBar 存在于导航栏控制器底部,且默认被隐藏!下面是 UIToolBar 的使用方式
// - AppDelegate.m
1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 2 // UIWidow 3 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 4 self.window.backgroundColor = [UIColor whiteColor]; 5 [self.window makeKeyAndVisible]; 6 // 根视图控制器 7 ViewController * vc = [[ViewController alloc] init]; 8 UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; 9 nav.navigationBar.translucent = NO; 10 self.window.rootViewController = nav; 11 return YES; 12 }
// - ViewController.m
1 #import "ViewController.h" 2 #import "AppDelegate.h" 3 @interface ViewController() 4 @property(nonatomic,strong)UIImageView *imageView; 5 @end 6 7 @implementation ViewController 8 - (void)viewDidLoad { 9 [super viewDidLoad]; 10 self.view.backgroundColor = [UIColor yellowColor]; 11 // 导航栏是否透明 12 // 半透明/隐藏:根视图从原点开始显示,大小同屏幕一致 13 // 不透明: 根视图从导航栏底部开始显示,高度 = 主屏幕高度 - 导航栏高度 14 15 // 在 APPDelegate.m 文件中,导航栏无论毛玻璃效果的设置与否 16 // 在该里打印根视图的 frame,其尺寸始终同屏幕大小保持一致 17 // 模拟器是 8 plus 18 NSLog(@"%@",NSStringFromCGRect(self.view.frame));// {{0, 0}, {414, 736}} 19 // 但是在 viewWillAppear:方法中 尺寸就会发生改变 20 // 原因是在执行 viewDidLoad 时,根视图还未显示 21 // 就是说该时根视图还没有跟导航控制器发生联系 22 23 // 也就意味着我们在 viewDidLoad:方法中 配置 toolbar 是没有任何效果的 24 // [self toolbarDemo]; 25 26 //---------------------------------- 27 // 导航栏的 左/右 标题 28 self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemReply target:self action:@selector(doClick:)]; 29 self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(doClick:)]; 30 } 31 32 // Toolbar 33 - (void)viewWillAppear:(BOOL)animated{ 34 [super viewWillAppear:YES]; 35 NSLog(@"%@",NSStringFromCGRect(self.view.frame)); 36 // {{0, 64}, {414, 672}} 37 [self toolbarDemo]; 38 39 NSLog(@"%@",NSStringFromCGRect(self.navigationController.toolbar.frame)); 40 // {{0, 687}, {414, 49}} 41 } 42 43 -(void)toolbarDemo{ 44 45 // 显示图片 46 self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, self.view.frame.size.width - 20, self.view.frame.size.height - 64-10)]; 47 self.imageView.backgroundColor = [UIColor whiteColor]; 48 self.imageView.image = [UIImage imageNamed:@"0.jpg"]; 49 [self.view addSubview:self.imageView]; 50 51 //--------------------- Toolbar ------------------- 52 53 // 显示时带有动画效果 54 // [self.navigationController setToolbarHidden:NO animated:YES]; 55 // 无动画效果 56 self.navigationController.toolbarHidden = NO; 57 self.navigationController.toolbar.translucent = YES; 58 self.navigationController.toolbar.backgroundColor = [UIColor greenColor]; 59 // 背景图片:尺寸要求同 navigationBar,这里图片尺寸 414*49 60 [self.navigationController.toolbar setBackgroundImage:[UIImage imageNamed:@"P414x49.png"] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault]; 61 62 [[UIToolbar appearance] 63 setBackgroundImage: [UIImage imageNamed:@"P414x49.png"] 64 forToolbarPosition: UIToolbarPositionAny 65 barMetrics: UIBarMetricsDefault]; 66 67 // 左:取消按钮 68 UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(toolbarAction:)]; 69 item1.tintColor = [UIColor whiteColor]; 70 71 // 工具栏按钮要显示图片的话,需做以下处理 72 UIImage *dealImage =[[self originImage:[UIImage imageNamed:@"toolItem.png"] scaleToSize:CGSizeMake(30, 30)] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 73 UIBarButtonItem *item0 = [[UIBarButtonItem alloc] initWithImage:dealImage style:UIBarButtonItemStylePlain target:self action:@selector(toolbarAction:)]; 74 75 //右:显示 HOT 76 UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:@"HOT" style:UIBarButtonItemStylePlain target:self action:@selector(toolbarAction:)]; 77 item2.tag = 103; 78 item2.tintColor = [UIColor whiteColor]; 79 80 // UIBarButtonSystemItemFlexibleSpace:自动确定宽度并均分 81 UIBarButtonItem *spaceButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 82 83 // 添加 item 84 self.toolbarItems = @[item1,spaceButtonItem,item0,spaceButtonItem,item2,]; 85 86 } 87 88 // 随机显示图片 89 - (void)toolbarAction:(UIBarButtonItem *)bItem{ 90 91 if (bItem.tag == 103) { 92 self.imageView.image =[UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",arc4random()%4+1]]; 93 }else{ 94 self.imageView.image = [UIImage imageNamed:@""]; 95 } 96 } 97 98 // 图片尺寸:会造成图片失真的问题 99 - (UIImage *)originImage:(UIImage*)image scaleToSize:(CGSize)size{ 100 UIGraphicsBeginImageContext(size); 101 [image drawInRect:CGRectMake(0,0, size.width, size.height)]; 102 UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext(); 103 UIGraphicsEndImageContext(); 104 return scaledImage; 105 } 106 107 // 如何查找 UINavigationController 108 - (void)doClick:(UIBarButtonItem*)barBT{ 109 110 if ([barBT isEqual:self.navigationItem.leftBarButtonItem]) { 111 //方式一:利用 window 112 NSLog(@"window:%@",self.view.window.rootViewController); 113 //方式二:控制器的自带属性 114 NSLog(@"self.navigationController:%@",self.navigationController); 115 }else{ 116 //方式三:使用 UIApplication(需引入头文件 AppDelegate.h) 117 NSLog(@"UIApplication:%@",((AppDelegate*)[UIApplication sharedApplication].delegate).window.rootViewController); 118 //方式四:响应者链 119 NSLog(@"响应者链:%@",[[[[[self.view nextResponder] nextResponder] nextResponder] nextResponder] nextResponder]); 120 } 121 } 122 123 @end
运行效果
TODO:代码 60行 toolBar 设置背景图片无效
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)