UITabBarController初次见面
今天,我们来剖析一下UITabBarController。首先,看一下one app的UITabBarController的效果
红色矩形框选的就是UITabBarController的tabBar控件。
UITabBarController基本用法
接下来,我们先学会如何使用UITabBarController。
基本使用步骤是:
1.创建子视图viewController
2.设置子视图viewController的tabBarItem属性
3.把子视图添加到UITabBarController
遵循以上的步骤原则,我们可以分析出来,one app 的tabBarController的实现代码。
//创建tabBarController
UITabBarController *tabBarController=[[UITabBarController alloc] init];
//创建home视图控制器,设置tabBarItem,然后添加到tabBarController
HomeViewController *homeViewController = [[HomeViewController alloc] init];
UINavigationController *homeNavigationController = [[UINavigationController alloc] initWithRootViewController:homeViewController];
homeNavigationController.tabBarItem.image = [UIImage imageNamed:@"tab_home_normal"];
homeNavigationController.tabBarItem.selectedImage =[UIImage imageNamed:@"tab_home_selected"];
[tabBarController addChildViewController:homeNavigationController];
//创建read视图控制器,设置tabBarItem,然后添加到tabBarController
ReadViewController *readViewController = [[ReadViewController alloc] init];
UINavigationController *readNavigationController = [[UINavigationController alloc] initWithRootViewController:readViewController];
readNavigationController.tabBarItem.image = [UIImage imageNamed:@"tab_read_normal"];
readNavigationController.tabBarItem.selectedImage =[UIImage imageNamed:@"tab_read_selected"];
[tabBarController addChildViewController:readNavigationController];
//创建music视图控制器,设置tabBarItem,然后添加到tabBarController
MusicViewController *musicViewController = [[MusicViewController alloc] init];
UINavigationController *musicNavigationController = [[UINavigationController alloc] initWithRootViewController:musicViewController];
musicNavigationController.tabBarItem.image = [UIImage imageNamed:@"tab_music_normal"];
musicNavigationController.tabBarItem.selectedImage =[UIImage imageNamed:@"tab_music_selected"];
[tabBarController addChildViewController:musicNavigationController];
//创建movie视图控制器,设置tabBarItem,然后添加到tabBarController
MovieViewController *movieViewController = [[MovieViewController alloc] init];
UINavigationController *movieNavigationController = [[UINavigationController alloc] initWithRootViewController:movieViewController];
movieNavigationController.tabBarItem.image = [UIImage imageNamed:@"tab_movie_normal"];
movieNavigationController.tabBarItem.selectedImage =[UIImage imageNamed:@"tab_movie_selected"];
[tabBarController addChildViewController:movieNavigationController];
UITabBarController解析
接下来,我有个问题需要提出来?
1.从创建tabBarController的过程,可以发现,我们先使用 [[HomeViewController alloc] init] 创建tabBarController,然后逐步向tabBarController添加子控制器。程序运行起来,就可以看见,tabBarController有多少个 子控制器,tabBarController的tabBar就会呈现多少个 按钮。那么问题来了,这个是如何做到 的呢?
首先,我们查看一下UITabBarController 类型的头文件
UITabBarController头文件中,几个重要的属性,我已经用红色的下划线标记出来了。
viewControllers属性 指明了tabBarController拥有多少个子视图控制器
seletedIndex属性 指明了当前哪一个子视图控制器 处于 选中状态,通过修改这个属性,可以告诉tabBarController选中哪一个子视图控制器
tabBar属性 是UIView类型的,它就是tabBarController最下面的那个包含多个按钮的 视图容器。至于显示多少个按钮,这个是由tabBarControllers的viewControllers数目决定的。
经过上面的分析,我们得到这个结论:tabBarController的tabBar上面的按钮数目是由tabBarController的viewControllers的数目决定的。那么tabBarController是在哪个方法创建tabBar上面的按钮的呢?
首先,可以肯定的是,绝对不会是初始化方法initWithFrame里面,因为,我们刚才说过了,我们是先创建tabBarController,然后逐一地向tabBarController添加子视图控制器。换就话说,调用initWithFrame的时候,我们还不知道有多少个子视图控制器。视图控制器初始化相关的工作,如果不是在initWithFrame方法里面执行的,就是在viewDidLoad里面执行的。下面列出tabBarController的viewDidLoad方法里面与tabBar相关的代码。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSMutableArray *tabBarItems=[NSMutableArray array];
for (UIViewController *controller in self.viewControllers) {
[tabBarItems addObject:controller.tabBarItem];
}
self.tabBar.items=tabBarItems;
}
上面的代码主要逻辑就是:遍历tabBarController的viewControllers,把viewController 的tabBarItem添加到数组里面,然后把数组赋值给tabBar视图的items属性。
这里需要详细说一下UIViewController的tabBarItem属性,它声明在UIViewController的分类UITabBarControllerItem里面。注意,UITabBarItem并不是继承自UIView,它只是一个普通NSObject,主要作用就是封装数据,这个数据用来设置tabBarController的tabBar视图上面的按钮。tabBarItem里面常用的属性和方法:
@property(nullable, nonatomic,copy) NSString *title; //设置按钮的文字
@property(nullable, nonatomic,strong) UIImage *image; //设置按钮 正常状态时候的图片
@property(nullable,nonatomic,strong)UIImage *selectedImage ; //设置按钮 选中状态的 图片
- (void)setTitleTextAttributes:(nullableNSDictionary<NSString *,id> *)attributes forState:(UIControlState)state; //设置按钮文字 的颜色、字体等属性
经过上面的分析,既然UITabBar通过属性items 获取到了tabBarItem数组之后,我们可以猜测一下,UITabBar一定会重写items的setter方法
- (void)setItems:(NSArray<UITabBarItem *> *)items{
for (UITabBarItem *barItem in items) {
UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];
//设置 按钮的正常状态/选中状态 的图片
[btn setImage:barItem.image forState:UIControlStateNormal];
[btn setImage:barItem.selectedImage forState:UIControlStateSelected];
[btn setTitle:barItem.title forState:UIControlStateNormal];
//设置按钮 正常状态时候 文字的颜色
NSDictionary *normalTextAttributes= [barItem titleTextAttributesForState:UIControlStateNormal];
UIColor *normalTextColor=[normalTextAttributes objectForKey:NSForegroundColorAttributeName];
if (normalTextColor) {
[btn setTitleColor:normalTextColor forState:UIControlStateNormal];
}
//设置按钮 选中状态时候 文字的颜色
NSDictionary *selectedTextAttributes= [barItem titleTextAttributesForState:UIControlStateNormal];
UIColor *selectedTextColor=[selectedTextAttributes objectForKey:NSForegroundColorAttributeName];
if (selectedTextColor) {
[btn setTitleColor:selectedTextColor forState:UIControlStateSelected];
}
//设置按钮的点击处理方法,将按钮添加到barBar
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:btn];
}
//重新布局
[self setNeedsLayout];
}
以上代码,实现了向UITabBar的添加按钮,但是,我们并没有给UIButton设置frame,我们知道,创建一个视图的时候,有两件事情是必须要做的:第一件,创建视图,完成视图的初始化。第二件,就是设置视图的frame,设置视图的空间布局。通常,我们是layoutSubViews方法里面添加 视图的布局代码。
- (void)layoutSubviews{
[super layoutSubviews];
CGFloat btnW=self.bounds.size.width/self.items.count;
CGFloat btnH=self.bounds.size.height;
for (int i=0; i<self.items.count; i++) {
UIButton *btn=[self.subviews objectAtIndex:i];
btn.frame=CGRectMake(btnW*i, 0, btnW, btnH);
}
}