IOS 學習筆記之基于 UITabBarController 的主流 APP 底部導航欄實現(xiàn)

前言

當app中有多個控制器的時候彪见,就需要對這些控制器進行管理,用一個控制器去管理其他多個控制器;如圖所示:

IOS UIView 提供了兩個特殊的控制器恨胚,UINavigationController和UITabBarController去管理其它控制器。

本文以下面的一個簡單例子加以說明基本用法:


UIWindow 和 UIViewController 的基本內(nèi)容

新建一個 Single View Application 工程灼卢,在iOS應用中绍哎,每個程序得main函數(shù)中都調(diào)用了UIApplicationMain函數(shù)。

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

先來看看UIApplicationMain函數(shù)的原型:

UIKIT_EXTERN int UIApplicationMain(
  int argc, 
  char *argv[], 
  NSString * __nullable principalClassName, 
  NSString * __nullable delegateClassName
);

前面的argc和argv是ISO C標準的main函數(shù)的參數(shù)鞋真,直接傳遞給UIApplicationMain進行相關(guān)處理崇堰,principalClassName是應用程序類的名字,該類必須繼承自UIApplication類涩咖,而delegateClassName是應用程序類的代理類海诲。如果主要nib文件(在info.plist文件中指定,key是NSMainNibFile)存在抠藕,就會在nib文件對象里尋找Application對象和連接它的delegate饿肺。此函數(shù)會根據(jù)principalClassName創(chuàng)建UIApplication對象,然后根據(jù)delegateClassName創(chuàng)建一個delegate對象盾似,并將UIApplication對象中的delegate屬性設置為delegate對象敬辣,接著會建立應用的main runloop,進行事件的處理零院,首先調(diào)用application:didFinishLaunchingWithOptions溉跃。程序正常退出時才返回(如今iOS支持后臺運行,系統(tǒng)在必要時會強行殺死不用的進程告抄,一般這個函數(shù)不等返回進程就終止了)撰茎。

// 程序啟動完成調(diào)用
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 創(chuàng)建Window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // 設置Window的背景顏色
    self.window.backgroundColor = [UIColor whiteColor];
    
    // 設置根控制器
    ViewController *vc = [[ViewController alloc] init];
    self.window.rootViewController = vc;

    // 設置并顯示主窗口
    [self.window makeKeyAndVisible];
    
    return YES;
}

UIWindow是一種特殊的UIView,通常在一個應用中只會有一個UIWindow打洼。在ios程序啟動完成后龄糊,建立的第一個視圖控件就是UIWindow,接著創(chuàng)建一個控制器的View募疮,最后將控制器的View添加到UIWindow上炫惩,于是控制器的View就是顯示到屏幕上了。一個ios程序之所以能顯示在屏幕上阿浓,完全是因為它有UIWindow他嚷,也就是說沒有UIWindow就看不到任何UI界面。

控制器的創(chuàng)建:

UIViewController *vc = [UIViewController alloc] init];

可以用isViewLoaded方法判斷一個UIViewController的view是否已經(jīng)被加載芭毙;控制器的view加載完畢就會調(diào)用viewDidLoad方法筋蓖。

將view添加到UIWindow:

  • 直接將view添加到UIWindow中,并不理會view對應的控制器退敦。
- (void)addSubView:(UIView *)view;
  • 通過設置根控制器歧斟,自動將rootViewController的view添加到UIWindow中宾娜,負責管理rootViewController的生命周期玖雁。
@property(nonatomic,retain) UIViewController *rootViewController;

獲取 RootViewController:

第一種方法:

UIWindow *window = [UIApplication sharedApplication].keyWindow;
UIViewController *rootViewController = window.rootViewController;

第二種方法:

AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
UIViewController *rootViewController = appdelegate.window.rootViewController;

UINavigationController 和 UITabBarController 的基本內(nèi)容

UINavigationController以棧的形式保存子控制器,使用push方法能將某個控制器壓入棧忠聚,使用pop方法可以移除棧頂控制器。

打開 ViewController 的方式:

 - (void)pushViewController:(UIViewController*)viewController animated:(BOOL)animated;

三種移除 ViewController 的方式:

將棧頂?shù)目刂破饕瞥?- (UIViewController*)popViewControllerAnimated:(BOOL)animated;
回到指定的子控制器
- (NSArray*)popToViewController:(UIViewController*)viewController animated:(BOOL)animated;
回到根控制器(棧底控制器)
- (NSArray*)popToRootViewControllerAnimated:(BOOL)animated;

初始化UINavigationController:

方法一:

UINavigationController *nv = [[UINavigationController alloc] init];  

方法二:

UINavigationController *nv = [[UINavigationController alloc] initWithRootViewController:rootViewController];

UITabBarController和UINavigationController類似,UITabBarController也可以輕松地管理多個控制器,輕松完成控制器之間的切換,典型的例子就是QQ唱捣、微信等應?。但是UITabBarController其管理的視圖一直存在,而UINavigationController在pop后會銷毀掉网梢,釋放內(nèi)存震缭。UITabBarController通常作為整個程序的rootViewController,而且不能添加到別的container viewController中战虏。

UITabBarController的使用步驟:

  1. 初始化UITabBarController
  2. 創(chuàng)建子控制器(viewcontroller)
  3. 把子控制器添加到UITabBarController
  4. 設置UIWindow的rootViewController為UITabBarController

將子控制器添加到UITabBarController:

方法一:添加單個子控制器

- (void)addChildViewController:(UIViewController*)childController;

方法二:添加多個子控制器

view.viewControllers = NSArray *childController;

UITabBarController中嵌套UINavigationController:

UINavigationController中嵌套UITabBarController:

項目實戰(zhàn)

將UITabBarController的邏輯提取到一個獨立的ViewController中拣宰。可以新建一個繼承于UITabBarController的ViewController烦感。

AppDelegate.m:

// 程序啟動完成調(diào)用
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 創(chuàng)建Window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // 設置Window的背景顏色
    self.window.backgroundColor = [UIColor whiteColor];
    
    // 設置根控制器
    ViewController *vc = [[ViewController alloc] init];
    self.window.rootViewController = vc;

    // 設置并顯示主窗口
    [self.window makeKeyAndVisible];
    
    return YES;
}

ViewController.h:

@interface ViewController : UITabBarController

@end

ViewController.m:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 創(chuàng)建子控制器
    HomeViewController *homeVC=[[HomeViewController alloc] init];
    [self setTabBarItem:homeVC.tabBarItem
                  title:@"首頁"
              titleSize:13.0
          titleFontName:@"HeiTi SC"
          selectedImage:@"i_tab_home_selected"
     selectedTitleColor:[UIColor redColor]
            normalImage:@"i_tab_home_normal"
       normalTitleColor:[UIColor grayColor]];
    
    BlogViewController *blogVC=[[BlogViewController alloc] init];
    [self setTabBarItem:blogVC.tabBarItem
                  title:@"博文"
              titleSize:13.0
          titleFontName:@"HeiTi SC"
          selectedImage:@"i_tab_blog_selected"
     selectedTitleColor:[UIColor redColor]
            normalImage:@"i_tab_blog_normal"
       normalTitleColor:[UIColor grayColor]];
    
    UINavigationController *homeNV = [[UINavigationController alloc] initWithRootViewController:homeVC];
    UINavigationController *blogNV = [[UINavigationController alloc] initWithRootViewController:blogVC];
    // 把子控制器添加到UITabBarController
    self.viewControllers = @[homeNV, blogNV];
}

我們通常需要對tabBarItem進行設置巡社,可以封裝一個setTabBarItem方法,只需要進行簡單的配置即可手趣。

- (void)setTabBarItem:(UITabBarItem *)tabbarItem
                title:(NSString *)title
            titleSize:(CGFloat)size
        titleFontName:(NSString *)fontName
        selectedImage:(NSString *)selectedImage
   selectedTitleColor:(UIColor *)selectColor
          normalImage:(NSString *)unselectedImage
     normalTitleColor:(UIColor *)unselectColor
{
    
    //設置圖片
    tabbarItem = [tabbarItem initWithTitle:title image:[[UIImage imageNamed:unselectedImage]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] selectedImage:[[UIImage imageNamed:selectedImage]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
    
    // S未選中字體顏色
    [[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName:unselectColor,NSFontAttributeName:[UIFont fontWithName:fontName size:size]} forState:UIControlStateNormal];
    
    // 選中字體顏色
    [[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName:selectColor,NSFontAttributeName:[UIFont fontWithName:fontName size:size]} forState:UIControlStateSelected];
}

然后對每個子ViewController進行自定義即可晌该,如BlogViewController.h可以這樣寫:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *helloBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, SCREEN_WIDTH - 200, 50)];
    helloBtn.backgroundColor = [UIColor redColor];
    [helloBtn setTitle:@"hello world" forState:UIControlStateNormal];
    [helloBtn addTarget:self action:@selector(showToast) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:helloBtn];
}

- (void)showToast{
    // 打開新ViewController
    BlogDetailViewController *blogDetail = [[BlogDetailViewController alloc] init];
    blogDetail.hidesBottomBarWhenPushed=YES;
    [self.navigationController pushViewController:blogDetail animated:YES];
}

源代碼:https://github.com/zhaomenghuan/learn-ios/tree/master/example/UITabBarController

參考

iOS -App主流框架UINavigationController && UITabBarController的簡單使用


我最近在 segmentfault 開了5+ App開的系列講座,歡迎前來圍觀:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绿渣,一起剝皮案震驚了整個濱河市朝群,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌中符,老刑警劉巖姜胖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異淀散,居然都是意外死亡右莱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門档插,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慢蜓,“玉大人,你說我怎么就攤上這事阀捅≌偷桑” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵饲鄙,是天一觀的道長凄诞。 經(jīng)常有香客問我,道長忍级,這世上最難降的妖魔是什么帆谍? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮轴咱,結(jié)果婚禮上汛蝙,老公的妹妹穿的比我還像新娘烈涮。我一直安慰自己,他們只是感情好窖剑,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布坚洽。 她就那樣靜靜地躺著,像睡著了一般西土。 火紅的嫁衣襯著肌膚如雪讶舰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天需了,我揣著相機與錄音跳昼,去河邊找鬼。 笑死肋乍,一個胖子當著我的面吹牛鹅颊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播墓造,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼堪伍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了滔岳?” 一聲冷哼從身側(cè)響起杠娱,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谱煤,沒想到半個月后摊求,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡刘离,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年室叉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片硫惕。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡茧痕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恼除,到底是詐尸還是另有隱情踪旷,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布豁辉,位于F島的核電站令野,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏徽级。R本人自食惡果不足惜气破,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望餐抢。 院中可真熱鬧现使,春花似錦低匙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至售碳,卻和暖如春渗稍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背团滥。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留报强,地道東北人灸姊。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像秉溉,于是被迫代替她去往敵國和親力惯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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