美文网首页iOSRDVTabBarController
读RDVTabBarController源码记录

读RDVTabBarController源码记录

作者: 一剑书生 | 来源:发表于2015-08-24 00:31 被阅读4104次

    RDVTabBarController 是一个定制化的TabBarController库,可动画显示隐藏tabbar栏,可定制tabbar栏,代码库地址在这,效果如下:

    iPhone-small.png

    用法与UITarbarController差不多,一开始需要设置它的ViewControllers

    RDVTabBarController *tabBarController = [[RDVTabBarController alloc] init];
    [tabBarController setViewControllers:@[firstNavigationController, secondNavigationController, thirdNavigationController]];
    

    具体的请看github上的介绍。

    接下来看看,TabBar栏是怎么被添加到TarbarController的view上,为什么它能在每个ViewController上都能显示的。

    首先,在RDVTabBarController类的viewDidLoad方法看到:

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        [self.view addSubview:[self contentView]];
        [self.view addSubview:[self tabBar]];
    }
    

    注意添加顺序,先添加contentView,后添加tabBar,这样tabBar栏就不会被contentView覆盖挡住了。此时view的视图层级是这样的:

    屏幕快照 2015-08-23 下午3.43.23.png

    只要设置一下它们的大小和位置,也就能变成这样:

    屏幕快照 2015-08-23 下午3.46.04.png

    接着看viewWillAppear方法:

    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        
        [self setSelectedIndex:[self selectedIndex]];
        
        [self setTabBarHidden:self.isTabBarHidden animated:NO];
    }
    

    先看里面的setSelectedIndex方法:

    - (void)setSelectedIndex:(NSUInteger)selectedIndex {
        if (selectedIndex >= self.viewControllers.count) {
            return;
        }
        //第一步
        if ([self selectedViewController]) {
            [[self selectedViewController] willMoveToParentViewController:nil]; //(1)
            [[[self selectedViewController] view] removeFromSuperview]; //(2)
            [[self selectedViewController] removeFromParentViewController]; //(3)
        }
        
        _selectedIndex = selectedIndex;
        [[self tabBar] setSelectedItem:[[self tabBar] items][selectedIndex]];
        //第二步
        [self setSelectedViewController:[[self viewControllers] objectAtIndex:selectedIndex]];
        [self addChildViewController:[self selectedViewController]];(1)
        [[[self selectedViewController] view] setFrame:[[self contentView] bounds]];
        [[self contentView] addSubview:[[self selectedViewController] view]];(2)
        [[self selectedViewController] didMoveToParentViewController:self];(3)
        
        [self setNeedsStatusBarAppearanceUpdate];
    }
    

    重点看,第一步,移除上一个所选的ViewController:
    (1)willMoveToParentViewController方法,传nil参数表示子视图控制器将被移除;
    (2)视图控制器的view从父视图中移除;
    (3)子视图控制器从父视图控制器中移除,会自动调用didMoveToParentViewController方法来通知回调。

    第二步,添加所选的ViewController:
    (1)添加视图控制器,会自动调用willMoveToParentViewController方法;
    (2)添加视图控制器的view;
    (3)完成添加视图控制器,
    要留意的是,是将ViewController的View添加到contentView中,而不是TabBarController的view。而以后push视图控制器的话,都是将视图控制器的view添加到contentView中,这样tabBar就始终能覆盖在contentView之上显示出来。

    再看RDVTabBarController类中的setTabBarHidden方法:

    - (void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated {
        _tabBarHidden = hidden;
        
        __weak RDVTabBarController *weakSelf = self;
        //动画中执行的block
        void (^block)() = ^{
            CGSize viewSize = weakSelf.view.bounds.size;
            CGFloat tabBarStartingY = viewSize.height;
            CGFloat contentViewHeight = viewSize.height;
            CGFloat tabBarHeight = CGRectGetHeight([[weakSelf tabBar] frame]);
            
            if (!tabBarHeight) {
                tabBarHeight = 49;//tabBar默认高度
            }
            
            if (!hidden) {
                tabBarStartingY = viewSize.height - tabBarHeight;
                if (![[weakSelf tabBar] isTranslucent]) {
                    contentViewHeight -= ([[weakSelf tabBar] minimumContentHeight] ?: tabBarHeight);
                }
                [[weakSelf tabBar] setHidden:NO];
            }
            
            [[weakSelf tabBar] setFrame:CGRectMake(0, tabBarStartingY, viewSize.width, tabBarHeight)];
            [[weakSelf contentView] setFrame:CGRectMake(0, 0, viewSize.width, contentViewHeight)];
        };
        //动画完成的block
        void (^completion)(BOOL) = ^(BOOL finished){
            if (hidden) {
                [[weakSelf tabBar] setHidden:YES];
            }
        };
        
        if (animated) {
            [UIView animateWithDuration:0.24 animations:block completion:completion]; //执行动画
        } else {
            block();
            completion(YES);
        }
    }
    

    这个方法是设置TabBar栏显示或隐藏,所使用的动画比较简单,动画中的block主要设置contentView和tabBar栏的大小和位置。而tabBar栏其实就是一个普通的view,通过设置它的hidden属性,就能让tabBar栏显示或隐藏。

    其实,通过分析RDVTabBarController源码,也就明白如何自定义一个容器视图控制器了,同时也能大概明白UITabBarController内部的组织结构了。

    最后,请看苹果官方文档:自定义视图控制器容器

    相关文章

      网友评论

      • feng_dev:这个库能 自定义 tabbar 吗? 就是 那种 中间是一个 button 的 tabbar 其他几个 有对应的界面,这个只是 button
      • 鸟人扎墨客:写的简单明了 非常好

      本文标题:读RDVTabBarController源码记录

      本文链接:https://www.haomeiwen.com/subject/tujxcttx.html