控制器及View的多種創建方式
- 創建控制器的3種方式?
- 直接通過alloc + init的方式創建。
- 創建一個“Single View Application”,刪除默認控制器、Main.storyboard、Main Interface設置為空。
- 創意一個自定義的控制器,FirstViewController。
- 在AppDelegate的application:didFinishLaunchingWithOptions:方法中創建UIWindow對象。
- 通過alloc + init的方式創建該控制器的對象,并設置該控制器view的背景色。
- 設置UIWindow的根控制器為該控制器對象。
- 通過加載storyboard文件來創建一個控制器。
- 刪除了Main.storyboard文件,也清空了Main Interface的配置,那么現在就需要自己創建一個新的storyboard文件(Two.storyboard), 然后拖一個控制器上去,在AppDelegate中自己寫代碼來加載Two.storyboard文件。
- 通過指定的xib文件來創建控制器。
- 創建一個自己的控制器類。
- 創建一個xib文件,在xib文件中拽一個UIView。
- 選中xib文件中的“File's Owner”,在屬性中設置對應的類(Class)是剛才創建的控制器類。“File's Owner”可以理解為,當前xib文件是為誰服務的。
- 然后選中“File's Owner”->“右擊”選中“view”->拖線到對應的view上。(設置該xib文件中哪個視圖是控制器默認要創建的視圖)
- 通過alloc + initWithNibName來創建。
- 直接通過alloc + init的方式創建。
// 一、直接通過alloc+init的方式創建
// 1.創建UIWindow
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 2.創建控制器
FirstViewController *vc1 = [[FirstViewController alloc] init];
vc1.view.backgroundColor = [UIColor blueColor];
// 3.設置控制器為UIWindow對象的根控器"rootViewController"
self.window.rootViewController = vc1;
// 4.顯示UIWindow對象
[self.window makeKeyAndVisible];
// 二、通過加載storyboard文件創建
// 1.加載對應的storyboard文件
UIStoryboard *myStoryboard = [UIStoryboard storyboardWithName:@"My" bundle:nil];
// 2.創建該storyboard中的被設置為"初始化控制器"(箭頭所指向的控制器)的對象。
UIViewController *vc2 = [myStoryboard instantiateInitialViewController];
// 3.根據storyboard中的控制器的storyboard ID來創建對應的控制器
UIViewController *vc3 = [myStoryboard instantiateViewControllerWithIdentifier:@"redVwController"];
// 4.設置控制器為UIWindow對象的根控制器"rootViewController"
self.window.rootViewController = vc2;
// 三、通過指定的 xib 文件來創建
// 1.通過xib文件, 創建控制器
FirstViewController *vc1 = [[FirstViewController alloc] initWithNibName:@"First" bundle:nil];
// 2.設置控制器為UIWindow對象的根控制器"rootViewController"
self.window.rootViewController = vc1;
- 創建控制器中的UIView?
- 控制器創建好以后,控制器所管理的view是如何創建的?
- 控制器的view是通過調用控制器的loadView方法來創建的。這個方法是UIViewController中的一個對象方法,只要控制器的loadView方法被調用了,那么證明控制器的view創建好了。
- 當調用完畢控制器的loadView方法以后,從這時開始,才創建好了控制器的view。
- 當控制器的view被創建好以后,緊接著就調用控制器的viewDidLoad方法。
- 控制器的view采用了懶加載的方式,也就是說,在需要的時候(在用到的時候)才會創建(調用loadView方法)。
- 注意:無論控制器是如何創建的,只要在控制器中,重寫了loadView方法,并且沒有調用
[super loadView];
方法,那么最終控制器的view就必須完全在loadView方法中自己來創建了,所以loadView方法可以用來自定義view。
- 控制器中的view創建:當第一次從self.view中獲取view的時候(第一次使用self.view的時候),控制器會調用它自己的loadView方法先創建一個view,并且把這個新創建的view設置給self.view。
- 如果是直接通過alloc + init方法創建的控制器,則
self.view = [[UIView alloc] init];
。 - 如果是通過storyboard創建的控制器,加載storyboard中的控制器,并把storyboard中的控制器中的view設置給self.view。
- 如果是通過加載xib創建的控制器,加載xib中的view,并把xib中的view設置給self.view。
- 如果是直接通過alloc + init方法創建的控制器,則
- 通過storyboard創建完控制器后,自動調用loadView方法,創建控制器的view。此時自定義的控制器,因為沒有“重寫”loadView方法,所以loadView方法內部就是根據storyboard文件中的view來創建view的。
- 通過xib文件創建完控制器后,自動調用loadView創建控制器的view。此時自定義的控制器,因為沒有“重寫”loadView方法,所以loadView方法內部就是根據xib文件中的view來創建view的。
- 如果創建控制器的時候,通過initWithNibName指定了xib的名字,那么就根據該xib創建view。
- 如果創建控制器的時候,沒有指定任何xib文件,也沒有相應的storyboard文件,那么會嘗試查找“與控制器名字相同的,但是去除Controller的文件名的xib文件”,如果還是沒有,會嘗試查找與控制器名字完全相同的xib文件,如果有,則使用該xib文件創建view。
- 建議:如果要使用某個xib文件名自動匹配的方式創建view,建議名字與控制器相同。
- 通過重寫UIViewController的loadView方法,自己通過代碼來創建控制器的view。
- 控制器的loadView方法就是用來自定義view的。如果要為控制器自定義view,要寫在loadView中,不要寫在viewDidLoad中。
- 如果重寫loadView方法中調用了
[super loadView];
,那么依然會使用默認的方式來加載。想自定義,應該不調用此方法。
- 無論是通過加載xib創建view,storyboard創建view,最終都依賴于loadView方法。
- 控制器的loadView方法什么時候調用?
- 在需要用到控制器的view的時候才調用,當調用UIWindow對象的makeKeyAndVisible方法時,就需要顯示該view了,此時就表示用到view了,這個就叫做“延遲加載”。
- 控制器創建好以后,控制器所管理的view是如何創建的?
多控制器管理
- 多控制器管理?
- 多控制器管理的思路:使用一個控制器來管理所有其他控制器,類似于使用一個UIView來管理其他的子view。
- 父控制器:管理其他控制器的控制器,就可以看做是“父控制器”、子控制器:被管理的控制器就是子控制器。
- iOS提供了兩個比較特殊的控制器(用來管理“控制器”的控制器):
- UINavigationController導航控制器,輕松管理多個控制器,并且控制不同控制器之間的跳轉和切換。
- UITabBarController也可以輕松地管理多個控制器,輕松完成控制器之間的切換。
- UINavigationController導航控制器?
- 使用步驟:
- 創建、初始化一個導航控制器:UINavigationController。
- 設置UIWindow的rootController為UINavigationController。
- 通過調用push方法添加子控制器到UINavigationController。
- 通過pop方法可以返回到上一個控制器。
- 注意:誰是最后一個push進來的,當前顯示的就是哪個viewController。
- 導航控制器的導航欄是從Y坐標20開始的,高度是44,導航欄上面的20高度是“狀態欄”。導航欄的內容由棧頂控制器的navigationItem屬性決定。
- UINavigationController導航控制器以棧的形式保存的子控制器。
- 使用步驟:
@property(nonatomic,copy) NSArray *viewControllers;
@property(nonatomic,readonly) NSArray *childViewControllers;
// 使用push方法能將某個控制器壓入棧
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
// 使用pop方法可以移除棧頂控制器
// 將棧頂的控制器移除
- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
// 回到指定的子控制器
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
// 回到根控制器(棧底控制器)
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated;
// 左上角的返回按鈕
@property(nonatomic,retain) UIBarButtonItem *backBarButtonItem;
// 中間的標題視圖
@property(nonatomic,retain) UIView *titleView;
// 中間的標題文字
@property(nonatomic,copy) NSString *title;
// 左上角的按鈕
@property(nonatomic,retain) UIBarButtonItem *leftBarButtonItem;
// 右上角的按鈕
@property(nonatomic,retain) UIBarButtonItem *rightBarButtonItem;
- UITabBarController?
- 使用步驟:
- 初始化UITabBarController。
- 設置UIWindow的rootViewController為UITabBarController。
- 根據具體情況,通過addChildViewController方法添加對應個數的子控制器。
- 如果UITabBarController有N個子控制器,那么UITabBar內部就會有N個UITabBarButton作為子控件。
- 使用步驟:
// 添加單個子控制器
- (void)addChildViewController:(UIViewController *)childController;
// 設置子控制器數組
@property (nonatomic,copy) NSArray *viewControllers;
// 標題文字
@property(nonatomic,copy) NSString *title;
// 圖標
@property(nonatomic,retain) UIImage *image;
// 選中時的圖標
@property(nonatomic,retain) UIImage *selectedImage;
// 提醒數字
@property(nonatomic,copy) NSString *badgeValue;
- App主流UI框架結構?
App主流UI框架結構
- Segue的介紹?
- storyboard上每一根用來界面跳轉的線,都是一個UIStoryboardSegue對象,簡稱Segue,表示延續、繼續的意思。
- 每一個segue對象,都有3個屬性:①唯一標識;②來源控制器;③目標控制器。
- 根據segue的執行(跳轉)時刻,segue可以分為2大類型:
- 自動型:點擊某個控件后,自動執行segue,自動完成界面跳轉。
- 手動型:需要通過寫代碼手動執行segue,才能完成界面跳轉。
- 自動型segue:
- 按住control鍵,直接從控件拖線到目標控制器。
- 如果點擊某個控件,不需要做任何判斷,直接跳轉到下一個界面,建議使用“自動型segue”。
- 手動型segue:
- 按住control鍵,從來源控制器拖線到目標控制器。
- 手動型的segue需要設置一個標識Identifier。
- 如果點擊某個控件,需要做一些處理之后才能跳轉到下一個界面,建議使用“手動型segue”。
- 利用某個控制器的
performSegueWithIdentifier:
對象方法可以執行當前控制器的某個Segue,跳轉界面:- self是來源控制器,只能通過來源控制器來調用該方法。
- 根據Identifier去storyboard中找到對應的線,新建UIStoryboardSegue對象。
- 設置Segue對象的sourceViewController(來源控制器)。
- 新建并且設置Segue對象的destinationViewController(目標控制器)。
- 調用sourceViewController來源控制器的
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
方法,做跳轉前的準備工作并傳入創建好的Segue對象。- sender就是調用performSegueWithIdentifier:sender:方法時傳入的對象。
- 調用Segue對象的
- (void)perform;
方法開始執行界面跳轉操作。 - 如果Segue的style是push,則取得sourceViewController所在的UINavigationController,調用UINavigationController的push方法將destinationViewController壓入棧中,完成跳轉。
- 如果Segue的style是modal調用sourceViewController的presentViewController方法將destinationViewController展示出來。
- Modal介紹?
- 除了push之外,還有另一種控制器的切換方式,那就是Modal,任何控制器都能通過modal的形式展示出來。
- modal的默認效果:新控制器從屏幕的最底部往上鉆,直到蓋住之前的控制器為止。
// 以modal的形式展示控制器
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion;
// 關閉當初modal出來的控制器
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion;
- 控制器的數據傳遞
- 順傳:
- 控制器的跳轉方向:A->B。
- 數據的傳遞方向:A->B。
- 數據的傳遞方式:在A控制器的
prepareForSegue:sender:
方法中根據Segue參數取得destinationViewController,也就是控制器B,直接給控制器B傳遞數據。 - 在B的
viewDidLoad
方法中取得數據,或者利用setter方法,設置界面上的UI控件。
控制器的數據傳遞(順傳)
- 逆傳:
- 控制器的跳轉方向:A->B。
- 數據的傳遞方向:B->A。
-
數據的傳遞方式:讓A成為B的代理,在B中調用A的代理方法,通過代理方法的參數傳遞數據給A。
控制器的數據傳遞(逆傳)
- 順傳: