一、UITabBarController简介
UITabBarController - 选项卡控制器,与导航控制器一样,也被广泛用于各种ios应用程序。顾名思义,选项卡控制器在屏幕底部显示一系列“选显卡”,这些选项卡表示为图标和文本,用户触摸它们将在不同的场景间切换。和UINavigationController类似,UITabBarController也可以用来控制多个页面导航,用户可以在多个视图控制器之间移动,并可以定制屏幕底部的选项卡栏。
借助屏幕底部的选项卡栏,UITabBarController不必像UINavigationController那样以栈的方式推入和推出视图,而是建立一系列的控制器(这些控制器可以是UIViewController、UINavigationController、UITableViewController等)并将它们添加到选项卡栏,使每个选项卡对应一个控制器。每个场景都呈现了应用程序的一项功能,或是提供了一种查看应用程序的独特方式。
二、UITabBarController的原理
当UITabBarController做为Window的根控制器时,程序一启动,UITabBarController就会一次性初始化所有子控制器,但是默认只加载第一个控制器视图,其他视图控制器只初始化,但默认不会加载,只有在需要显示的时候才调用loadView方法加载。特殊情况:在AppDelegate中设置其他的子控制器视图的背景颜色,就会提前加载该控制器视图,但不显示该视图。
每一个控制器视图只加载一次,就会一直存在内存中,当切换子控制器时直接显示,不显示在屏幕上的子控制器不会被销毁。当遇到内存警告时,会释放掉没有加载的子控制器。
每个视图控制器都有一个tabBarController属性,通过它可以访问所在的UITabBarController,而且对于UITabBarController的直接子视图,其tabBarController属性相当于它的父视图parentViewController。
每个视图控制器都有一个tabBarItem属性,通过它控制视图在UITabBarController的tabBar中的显示信息
tabBarItem的image属性必须是png格式(建议大小32*32),并且打开alpha通道否则无法正常显示。
当往UITabBarController添加子控制器,标签栏就会有序的自动生成对应的UITabBarButton对象,有多少个子控制器,标签栏就有多少个UITabBarButton对象,但是子控制器的数量超过5个的时候,标签栏上的第五个UITabBarButton对象就会显示成”More”类型的按钮。
其他注意点:
- UITabBarController没有根控制器的概念。在添加了相同的子控制器,不会增加tabitem的数量。子控器可以是UIViewController、UINavigationController、UITableViewController或者其他的视图控制器
- UITabBarButton在UITabBar中的位置是均分的,UITabBar的高度为49,UITabBarButton⾥面显⽰什么内容,由对应子控制器的tabBarItem属性来决定
- UITabBarController一般作为应用程序的rootViewController,但是它不能作为UINavigationController的根控制器
- UITabBarController默认只支持竖屏,当设备方向放生变化时候,它会查询viewControllers属性中包含的所有ViewController,仅当所有的viewController都支持该方向时,UITabBarController才会发生旋转,否则默认的竖向
- UITabBar继承于UIView,方便用户切换到对应的界面,当往标签控制器里添加子控制器,标签栏就会有序的自动生成对应的标签;创建一个标签控制器,就默认创建一个标签栏,标签栏最多显示5个标签
三、UI结构与源码结构图解
![](data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=)
四、基本使用
基本使用流程:
- 初始化UITabBarController
- 设置UIWindow的rootViewController为UITabBarController
- 创建相应的子控制器(viewcontroller)
- 把子控制器添加到UITabBarController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| -(void)useSystemTabBarControoler{ // 创建窗口 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; //1 创建标签控制器 UITabBarController *tabBarC = [[UITabBarController alloc] init]; //2 设置窗口的根控制器为标签控制器 self.window.rootViewController = tabBarC; // 显示窗口 [self.window makeKeyAndVisible];
//3 创建相应的子控制器 ViewController *v1 = [[ViewController alloc] init]; v1.tabBarItem.title = @"首页"; v1.tabBarItem.selectedImage = [UIImage imageNamed:@""]; v1.tabBarItem.badgeValue = @"10";
ViewController *v2 = [[ViewController alloc] init]; UINavigationController *nav2 = [[UINavigationController alloc] initWithRootViewController:v2]; nav2.tabBarItem.title = @"我的"; nav2.tabBarItem.selectedImage = [UIImage imageNamed:@""]; //4 把子控制器添加到UITabBarController tabBarC.viewControllers = @[v1,nav2];
// 设置标签栏的背景图片 tabBarC.tabBar.backgroundImage = [UIImage imageNamed:@"Snip20160825_2"]; }
|
该方式的弊端:
五、自定义使用
以自定义的方式实现UITabBaController
步骤:
- 新建一个继承自UITabBarController的子类
- 将这个子类设置为根控制器
- 在这个子类里面实现添加子控制器的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| //在自定义的UITaBBarController子类中:
-(void)addEachControllerWithName:(NSString *)controller andTitle:(NSString *)title andDefaultImage:(NSString *)defaultImage andSelectedImage:(NSString *)selectedImage{
// 添加子控制器 Class class = NSClassFromString(controller); UIViewController *VC01 = [[class alloc] init];
#pragma mark -- 文字效果设置 // 设置标题 VC01.tabBarItem.title = title; //文字和图片一样是默认的蓝色,所以也要进行设置才能达到自己想要的效果 //方案一: 通过setTitleTextAttributes属性设置(但是这个方法很麻烦,每次设置的时候都需要写很多代码 // 设置文字属性 NSMutableDictionary * attrs = [NSMutableDictionary dictionaryWithObjectsAndKeys: [UIFont systemFontOfSize:12.0],NSFontAttributeName, [UIColor brownColor],NSForegroundColorAttributeName, nil]; [VC01.tabBarItem setTitleTextAttributes:attrs forState:UIControlStateSelected]; #pragma mark -- 图片设置 // 设置默认图片 VC01.tabBarItem.image = [UIImage imageNamed:defaultImage];
//这种情况下因为有系统默认的蓝色渲染,会导致选中图标selectedImage不是图片原来的样子,可以通过以下两种方式解决 UIImage * image = [UIImage imageNamed:selectedImage]; //方法1 设置渲染模式 - 保持原始的渲染 //方法2:直接在图片文件夹的属性里面进行设置 - 将render as设置成original image image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; // 设置选中图片 VC01.tabBarItem.selectedImage =image;
VC01.view.backgroundColor = [UIColor yellowColor];
[self addChildViewController:VC01]; }
|
- 由于文字属性每次设置setTitleTextAttributes的时候代码很多很烦,所以要进行简化
- 当方法方法后面有UI_APPERANCE宏的时候,就可以通过appearance对象一次性设置
步骤
- 拿到那个item的apperance
- 对这个item进行设置、
- 之后所有的item都会是这个属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| //在自定义的UITabBarController子类中
//当方法方法后面有UI_APPERANCE宏的时候,就可以通过appearance对象一次性设置 //- (void)setTitleTextAttributes:(nullable NSDictionary<NSString *,id> *)attributes forState:(UIControlState)state NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; -(void)settingTitleColorByAppearance{ // 通过appearance统一设置UITabbarItem的文字属性 NSMutableDictionary * attrs = [NSMutableDictionary dictionary]; attrs[NSFontAttributeName] = [UIFont systemFontOfSize:12.0]; // 设置文字大小 attrs[NSForegroundColorAttributeName] = [UIColor grayColor]; // 设置文字的前景色
NSMutableDictionary * selectedAttrs = [NSMutableDictionary dictionary]; selectedAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:15.0]; selectedAttrs[NSForegroundColorAttributeName] = [UIColor redColor];
UITabBarItem * item = [UITabBarItem appearance]; // 设置appearance [item setTitleTextAttributes:attrs forState:UIControlStateNormal]; [item setTitleTextAttributes:selectedAttrs forState:UIControlStateSelected]; }
|
自定义底部tabbar(重点部分)
覆盖UITabBarController自带的tabBar为自定义的tabBar操作原理
- tabBar上的按钮是在UITabBarController的viewDidAppear的时候拿到 self.tabBar 再调用addSubViews添加上去的;
- 在viewDidAppear之前把控制器的tabBar换成我们自己的tabBar,就可以把tabBar上的按钮添加到自己的tabBar上;
- 但是tabBar控制器的tabBar属性是只读的,不能直接赋值,只能通过KVC模式跟换tabbar
步骤
- 新建一个继承自UITabbar的类
- 在这个类里面实现初始化
- 在
layoutSubviews
方法里面重新布局
- 在TabbarController里面跟换tabbar
- 虽然我们在TabbarController里面换成了自定义的tabbar,但是因为这个tabbar继承自uitabbar,所以它原来的属性和内容还在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #import "YLCustomTabBar.h"
@interface YLCustomTabBar()
/** 发布按钮 */ @property (nonatomic, weak) UIButton * publishBtn;
@end
@implementation YLCustomTabBar
/** * 初始化 */ - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) {
// 设置tabbar的子控件 UIButton * publishBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [publishBtn setBackgroundImage:[UIImage imageNamed:@"Add_Center"] forState:UIControlStateNormal]; [publishBtn setBackgroundImage:[UIImage imageNamed:@"Add_Center"] forState:UIControlStateHighlighted]; [publishBtn sizeToFit];
[self addSubview:publishBtn]; self.publishBtn = publishBtn; } return self; }
/** * 重写布局子控件的方法进行布局 */ - (void)layoutSubviews{ [super layoutSubviews]; NSLog(@"重新布局");
// 1.设置加号按钮的位置 CGPoint temp =self.publishBtn.center; temp.x=self.frame.size.width/2; temp.y=self.frame.size.height/2; self.publishBtn.center=temp;
// 2.设置其它UITabBarButton的位置和尺寸 CGFloat tabbarButtonW =self.frame.size.width /3; CGFloat tabbarButtonIndex =0; for (UIView *child in self.subviews) { Class class = NSClassFromString(@"UITabBarButton"); if ([child isKindOfClass:class]) { // 设置宽度 CGRect temp1=child.frame; temp1.size.width=tabbarButtonW; temp1.origin.x=tabbarButtonIndex * tabbarButtonW; child.frame=temp1; // 增加索引 tabbarButtonIndex++; if (tabbarButtonIndex ==1) {//如果底部有5个按钮这里就是2 tabbarButtonIndex++; } NSLog(@"frame----%f",child.frame.origin.x); } } } @end //在自定义的UITaBBarController子类中: [self setValue:[[YLCustomTabBar alloc]init] forKeyPath:@"tabBar"];
|
![Demo地址:https://github.com/yuanliangYL/iOSUITabBarControllerDeepUsing]