本文对UITabBarController进行分析,研究苹果内部是怎么构造出这个类的,以及我们怎么去自定义一个类

1、内部实现细节分析
我们尝试去打印tabBar,看看一个没有进行操作的UITarBarController是怎么样的:
[objc]  view plain copy
  1. UITabBarController *tabBarController = [[UITabBarController alloc]init];  
  2. NSLog(@"%@",tabBarController.tabBar.subviews);  
结果发现打印出来是这样的:
[objc]  view plain copy
  1. (  
  2. )  
(>_<) 是空的,不过没关系,我们可以通过写一个继承于UITabBarController的类,来查看内部细节

新建一个继承于UITabBarController类的类NTTabBarController,然后在viewDidLoad中为self添加4个子控制器接着 在viewDidAppear中打印这样一句代码(在viewDidLoad中打印是没有结果的)
[objc]  view plain copy
  1. - (void)viewDidAppear:(BOOL)animated  
  2. {  
  3.     NTLog(@"%@",self.tabBar.subviews);  
  4. }  
打印出来的结果是这样:
[objc]  view plain copy
  1. (  
  2.     "<_UITabBarBackgroundView: 0x7fcd927a1b40; frame = (0 0; 320 49); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fcd927070c0>>",  
  3.     "<UITabBarButton: 0x7fcd92453690; frame = (2 1; 76 48); opaque = NO; layer = <CALayer: 0x7fcd92454640>>",  
  4.     "<UITabBarButton: 0x7fcd9279d810; frame = (82 1; 76 48); opaque = NO; layer = <CALayer: 0x7fcd92426010>>",  
  5.     "<UITabBarButton: 0x7fcd92458a80; frame = (162 1; 76 48); opaque = NO; layer = <CALayer: 0x7fcd92459450>>",  
  6.     "<UITabBarButton: 0x7fcd9245c4b0; frame = (242 1; 76 48); opaque = NO; layer = <CALayer: 0x7fcd92426570>>",  
  7.     "<UIImageView: 0x7fcd9245db40; frame = (0 -0.5; 320 0.5); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fcd92426de0>>"  
  8. )  
在分析之前,需要明确几个参数值,导航栏的高度是49,iphone5之前屏幕宽度都是320,iphone6的屏幕宽度是375,iphone6 plus的屏幕宽度是414。
(1)第一个是UITabBarBackgroundView类,我们好像从来都没有使用过这个类,接着去试着敲出这个类,发现没有提示,那么就说明这个类是私有的,苹果不希望外部去访问和操作它。不过通过这个类的命名以及frame来看,这个类是tarBar中于背景相关的。
(2)最后一个是UIImageView类,这个对于大家当然是很熟悉的,通过看它的frame,它的宽度是320,然后高度仅仅为0.5,那么我们联想到的是tabBar中的最上面的分割线。
(3)中间有4个UITabBarButton类的对象,这个类也是私有的,通过查看frame,可以知道苹果所设计的tabBar中都是宽76,高48这样的尺寸的。

了解完了内部结构之后,进一步深入到tarBar中去讨论:新建一个继承于UITabBar的类NTTabBar,同时在以上所使用的NTTabBarController中去使用NTTabBar而不是系统所给的UITabBar,导入NTTabBar类,我们尝试去赋值self.tarBar:
[objc]  view plain copy
  1. self.tabBar = [[NTTabBar alloc]init];  
但是xcode报错,错误为:
Assignment to readonly property --->试图修改只读属性,按住command然后点击tarBar,在文章中发现:
[objc]  view plain copy
  1. @property(nonatomic,readonlyUITabBar *tabBar  
那么这时候我们可以使用KVC进行修改,无论属性是通过什么来修饰的,都是可以使用KVC进行赋值修改的:
[objc]  view plain copy
  1. [self setValue:[[NTTabBar alloc]init] forKeyPath:@"tabBar"];  
这时候就可以在我们自定义的NTTabBar类中进行详细操作:
我们知道对于一个控件中子控件的排布,都是写在了layoutSubViews里面。我们在自定义的NTTabBar中去重写layoutSubViews方法:
[objc]  view plain copy
  1. - (void)layoutSubviews  
  2. {  
  3.     NSLog(@"%@",self.subviews);  
  4. }  
这样打印的结果为:
[objc]  view plain copy
  1. (  
  2.     "<UITabBarButton: 0x7fe5b9c3ed00; frame = (2 1; 76 48); opaque = NO; layer = <CALayer: 0x7fe5b9c3fcb0>>",  
  3.     "<UITabBarButton: 0x7fe5b9f9eaa0; frame = (82 1; 76 48); opaque = NO; layer = <CALayer: 0x7fe5b9f9afc0>>",  
  4.     "<UITabBarButton: 0x7fe5b9fa92a0; frame = (162 1; 76 48); opaque = NO; layer = <CALayer: 0x7fe5b9f9e710>>",  
  5.     "<UITabBarButton: 0x7fe5b9e6dbf0; frame = (242 1; 76 48); opaque = NO; layer = <CALayer: 0x7fe5b9e6e0a0>>"  
  6. )  
可以发现,这里只有我们添加到4个子控制器对应的UITabBarButton,而没有那个作为背景的UITabBarBackgroundView,和作为分隔线的UIImageView。
我们又尝试修改:
[objc]  view plain copy
  1. - (void)layoutSubviews  
  2. {  
  3.     [super layoutSubviews];  
  4.     NSLog(@"%@",self.subviews);  
  5. }  
这样打印出来的结果为:
[objc]  view plain copy
  1. (  
  2.     "<_UITabBarBackgroundView: 0x7fa952c17ab0; frame = (0 0; 320 49); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fa952c7f430>>",  
  3.     "<UITabBarButton: 0x7fa952d52d30; frame = (2 1; 76 48); opaque = NO; layer = <CALayer: 0x7fa952d53d20>>",  
  4.     "<UITabBarButton: 0x7fa952ccd770; frame = (82 1; 76 48); opaque = NO; layer = <CALayer: 0x7fa952ccd5d0>>",  
  5.     "<UITabBarButton: 0x7fa952e3ea80; frame = (162 1; 76 48); opaque = NO; layer = <CALayer: 0x7fa952e3f370>>",  
  6.     "<UITabBarButton: 0x7fa952e42370; frame = (242 1; 76 48); opaque = NO; layer = <CALayer: 0x7fa952e3e970>>",  
  7.     "<UIImageView: 0x7fa952e4af60; frame = (0 -0.5; 320 0.5); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fa952e36650>>"  
  8. )  
这时候那两个控件就出来了,这是因为调用了super的方法。

2、重写构造tarBar内部结构
首先需要明确的是,对于UIView类或者是UIView类的子类,我们都需要在layoutSubViews里面去控制,所以我们在layoutSubViews里面进行重新布局(本例是模仿新浪微博的tarBar):
[objc]  view plain copy
  1. #import "NTTabBar.h"  
  2.   
  3. @interface NTTabBar()  
  4. @property (nonatomic , strongUIButton *middleButton;  
  5. @end  
  6.   
  7. @implementation NTTabBar  
  8.   
  9. // 懒加载  
  10. - (UIButton *)middleButton  
  11. {  
  12.     if (_middleButton == nil) {  
  13.         _middleButton = [UIButton buttonWithType:UIButtonTypeCustom];  
  14.         [_middleButton setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button"] forState:UIControlStateNormal];  
  15.         [_middleButton setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];  
  16.         [_middleButton setImage:[UIImage imageNamed:@"tabbar_compose_icon_add" ] forState:UIControlStateNormal];  
  17.         [_middleButton setImage:[UIImage imageNamed:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted];  
  18.     }  
  19.     return _middleButton;  
  20. }  
  21.   
  22. - (void)layoutSubviews  
  23. {  
  24.     // 调用super的方法为了创建UIImageView的分割线,和UITabBarBackgroundView的背景控件  
  25.     [super layoutSubviews];  
  26.       
  27.     int index = 0;  
  28.     for (UIView *view in self.subviews) {  
  29.         // 通过判断class的类型来过滤掉背景控件和分割线控件  
  30.         if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) {  
  31.             // 设置view的宽度  
  32.             view.width = 320 / 5;  
  33.             // 设置view的x--->由index来控制  
  34.             view.x = index * 320/5;  
  35.             // 再第三个位子留一个空位给自定义的middleButton  
  36.             if(index == 1){  
  37.                 index++;  
  38.                 // 创建middleButton并添加到tarBar  
  39.                 self.middleButton.height = 48;  
  40.                 self.middleButton.width = 320/5;  
  41.                 self.middleButton.x = index * 320/5;  
  42.                 self.middleButton.y = 2;  
  43.                 [self addSubview:self.middleButton];  
  44.             }  
  45.             index++;  
  46.         }  
  47.     }  
  48. }  
  49. @end  
通过在layoutSubViews方法中对进行操作,使得tarBar就变为了我们希望看到的效果:












评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值