讀RDVTabBarController源碼記錄

RDVTabBarController 是一個定制化的TabBarController庫,可動畫顯示隱藏tabbar欄,可定制tabbar欄,代碼庫地址在這,效果如下:

iPhone-small.png

用法與UITarbarController差不多,一開始需要設(shè)置它的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

只要設(shè)置一下它們的大小和位置,也就能變成這樣:

屏幕快照 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];
}

重點(diǎn)看,第一步,移除上一個所選的ViewController:
(1)willMoveToParentViewController方法,傳nil參數(shù)表示子視圖控制器將被移除;
(2)視圖控制器的view從父視圖中移除;
(3)子視圖控制器從父視圖控制器中移除,會自動調(diào)用didMoveToParentViewController方法來通知回調(diào)。

第二步,添加所選的ViewController:
(1)添加視圖控制器,會自動調(diào)用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;
    //動畫中執(zhí)行的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默認(rèn)高度
        }
        
        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]; //執(zhí)行動畫
    } else {
        block();
        completion(YES);
    }
}

這個方法是設(shè)置TabBar欄顯示或隱藏,所使用的動畫比較簡單,動畫中的block主要設(shè)置contentView和tabBar欄的大小和位置。而tabBar欄其實(shí)就是一個普通的view,通過設(shè)置它的hidden屬性,就能讓tabBar欄顯示或隱藏。

其實(shí),通過分析RDVTabBarController源碼,也就明白如何自定義一個容器視圖控制器了,同時也能大概明白UITabBarController內(nèi)部的組織結(jié)構(gòu)了。

最后,請看蘋果官方文檔:自定義視圖控制器容器

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,198評論 4 61
  • 文/煙雨雨巷 翻完蕭紅的《呼河蘭傳》,我深深地嘆了一口氣。怎么說呢,從好奇到悲哀到痛惋,從頭至尾都是吊著一口氣在那...
    煙雨雨巷閱讀 678評論 0 3
  • 有人說,夢想是殘燭之光火,現(xiàn)實(shí)是缺氧的空氣,在現(xiàn)實(shí)面前,夢想只是瞬間光火,不可一提。 翻閱起曾經(jīng)許下的承諾與誓言,...
    雲(yún)易少爺閱讀 392評論 0 5
  • 作者:趙鐵夫 我的心是 山腳下 白云邊 湖水旁的 青青草地 朝夕往復(fù) 過客來去 終有人會 悄悄地在草地上 拉上一堆...
    趙鐵夫閱讀 508評論 0 0
  • 今天一直在外忙碌,手機(jī)沒電啦!剛到家又要去接出差回家的串兒。怕來不及打卡,將之前存的天然酵母,無添加饅頭做...
    車前小草閱讀 483評論 5 2