[置顶] iOS中UITabBarController的剖析
2015-10-14 21:28
691 查看
本文对UITabBarController进行分析,研究苹果内部是怎么构造出这个类的,以及我们怎么去自定义一个类
1、内部实现细节分析我们尝试去打印tabBar,看看一个没有进行操作的UITarBarController是怎么样的:
UITabBarController *tabBarController = [[UITabBarController alloc]init]; NSLog(@"%@",tabBarController.tabBar.subviews);结果发现打印出来是这样的:
( )(>_<) 是空的,不过没关系,我们可以通过写一个继承于UITabBarController的类,来查看内部细节
新建一个继承于UITabBarController类的类NTTabBarController,然后在viewDidLoad中为self添加4个子控制器接着在viewDidAppear中打印这样一句代码(在viewDidLoad中打印是没有结果的)
- (void)viewDidAppear:(BOOL)animated { NTLog(@"%@",self.tabBar.subviews); }打印出来的结果是这样:
( "<_UITabBarBackgroundView: 0x7fcd927a1b40; frame = (0 0; 320 49); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fcd927070c0>>", "<UITabBarButton: 0x7fcd92453690; frame = (2 1; 76 48); opaque = NO; layer = <CALayer: 0x7fcd92454640>>", "<UITabBarButton: 0x7fcd9279d810; frame = (82 1; 76 48); opaque = NO; layer = <CALayer: 0x7fcd92426010>>", "<UITabBarButton: 0x7fcd92458a80; frame = (162 1; 76 48); opaque = NO; layer = <CALayer: 0x7fcd92459450>>", "<UITabBarButton: 0x7fcd9245c4b0; frame = (242 1; 76 48); opaque = NO; layer = <CALayer: 0x7fcd92426570>>", "<UIImageView: 0x7fcd9245db40; frame = (0 -0.5; 320 0.5); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fcd92426de0>>" )在分析之前,需要明确几个参数值,导航栏的高度是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:
self.tabBar = [[NTTabBar alloc]init];但是xcode报错,错误为:
Assignment to readonly property --->试图修改只读属性,按住command然后点击tarBar,在文章中发现:
@property(nonatomic,readonly) UITabBar *tabBar那么这时候我们可以使用KVC进行修改,无论属性是通过什么来修饰的,都是可以使用KVC进行赋值修改的:
[self setValue:[[NTTabBar alloc]init] forKeyPath:@"tabBar"];这时候就可以在我们自定义的NTTabBar类中进行详细操作:
我们知道对于一个控件中子控件的排布,都是写在了layoutSubViews里面。我们在自定义的NTTabBar中去重写layoutSubViews方法:
- (void)layoutSubviews { NSLog(@"%@",self.subviews); }这样打印的结果为:
( "<UITabBarButton: 0x7fe5b9c3ed00; frame = (2 1; 76 48); opaque = NO; layer = <CALayer: 0x7fe5b9c3fcb0>>", "<UITabBarButton: 0x7fe5b9f9eaa0; frame = (82 1; 76 48); opaque = NO; layer = <CALayer: 0x7fe5b9f9afc0>>", "<UITabBarButton: 0x7fe5b9fa92a0; frame = (162 1; 76 48); opaque = NO; layer = <CALayer: 0x7fe5b9f9e710>>", "<UITabBarButton: 0x7fe5b9e6dbf0; frame = (242 1; 76 48); opaque = NO; layer = <CALayer: 0x7fe5b9e6e0a0>>" )可以发现,这里只有我们添加到4个子控制器对应的UITabBarButton,而没有那个作为背景的UITabBarBackgroundView,和作为分隔线的UIImageView。
我们又尝试修改:
- (void)layoutSubviews { [super layoutSubviews]; NSLog(@"%@",self.subviews); }这样打印出来的结果为:
( "<_UITabBarBackgroundView: 0x7fa952c17ab0; frame = (0 0; 320 49); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fa952c7f430>>", "<UITabBarButton: 0x7fa952d52d30; frame = (2 1; 76 48); opaque = NO; layer = <CALayer: 0x7fa952d53d20>>", "<UITabBarButton: 0x7fa952ccd770; frame = (82 1; 76 48); opaque = NO; layer = <CALayer: 0x7fa952ccd5d0>>", "<UITabBarButton: 0x7fa952e3ea80; frame = (162 1; 76 48); opaque = NO; layer = <CALayer: 0x7fa952e3f370>>", "<UITabBarButton: 0x7fa952e42370; frame = (242 1; 76 48); opaque = NO; layer = <CALayer: 0x7fa952e3e970>>", "<UIImageView: 0x7fa952e4af60; frame = (0 -0.5; 320 0.5); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fa952e36650>>" )这时候那两个控件就出来了,这是因为调用了super的方法。
2、重写构造tarBar内部结构
首先需要明确的是,对于UIView类或者是UIView类的子类,我们都需要在layoutSubViews里面去控制,所以我们在layoutSubViews里面进行重新布局(本例是模仿新浪微博的tarBar):
#import "NTTabBar.h" @interface NTTabBar() @property (nonatomic , strong) UIButton *middleButton; @end @implementation NTTabBar // 懒加载 - (UIButton *)middleButton { if (_middleButton == nil) { _middleButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_middleButton setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button"] forState:UIControlStateNormal]; [_middleButton setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted]; [_middleButton setImage:[UIImage imageNamed:@"tabbar_compose_icon_add" ] forState:UIControlStateNormal]; [_middleButton setImage:[UIImage imageNamed:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted]; } return _middleButton; } - (void)layoutSubviews { // 调用super的方法为了创建UIImageView的分割线,和UITabBarBackgroundView的背景控件 [super layoutSubviews]; int index = 0; for (UIView *view in self.subviews) { // 通过判断class的类型来过滤掉背景控件和分割线控件 if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) { // 设置view的宽度 view.width = 320 / 5; // 设置view的x--->由index来控制 view.x = index * 320/5; // 再第三个位子留一个空位给自定义的middleButton if(index == 1){ index++; // 创建middleButton并添加到tarBar self.middleButton.height = 48; self.middleButton.width = 320/5; self.middleButton.x = index * 320/5; self.middleButton.y = 2; [self addSubview:self.middleButton]; } index++; } } } @end通过在layoutSubViews方法中对进行操作,使得tarBar就变为了我们希望看到的效果:
相关文章推荐
- UI - UITableView
- PostgreSQL attr correlation for values(logical order) & ctid (physcial order)
- burp suite中国乱码的解决方案
- UI - SendValue
- Android之UI布局
- UI - UINavigationController
- [PAT (Advanced Level) ]1007. Maximum Subsequence Sum 解题文档
- java复习:”Sting类、StringBuffer类、StringBuilder类的应用
- iOS UIView autoresizingMask
- PostgreSQL security usage guide
- PostgreSQL function's SECURITY DEFINER | INVOKER, SET configuration_parameter { TO value | = value |
- UITableView / UITableViewDataSource / UITableViewDelegate
- 《iOS Human Interface Guidelines》——Navigation
- CALayer的position,anchorPoint属性 与UIView的frame 属性
- UICollectionView
- ajax ExecuteNonQuery
- Buildbot初探
- 1007. Maximum Subsequence Sum
- 60 Permutation Sequence
- iOS之UIView简单动画