理解UITabBarController

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);
    }
}


好了,以上所有代码并没有经过测试,仅仅用来表达创建 UITabBarController 的barBar的思路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值