前言
當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的使用步驟:
- 初始化UITabBarController
- 創(chuàng)建子控制器(viewcontroller)
- 把子控制器添加到UITabBarController
- 設置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開的系列講座,歡迎前來圍觀: