初學IOS-UIViewController
初學IOS,本文翻譯了一些IOS官網上的UIViewController的知識點,如有不到位或不正確的地方,還請指正:
本文所介紹的內容的目標:
理解content view controllers 和 container view controllers
知道如何實現自定義view controller containers 以及 何時使用view controller containers
在iOS5操作系統下使用UIPageViewController
分享一些新的API和使用技巧
這是一個UIViewController
我們爲什麼要使用視圖控制器(View Controllers)?
兩個原因
- 使用它能夠做出更高品質的APP
- 它們可被繼承
視圖控制器(基礎知識)
設計模式
它們是MVC中的C
它們管理着“整個屏幕裏顯示的內容”
它們通常和它們的對象模型打包在一起
使用系統視圖控制器(System View Controllers)
系統視圖控制器通包括以下5種
TWTweetComposeViewController
UIImagePickerController
EKEventViewController
MFMailComposeViewController
MPMediaPickerController
設計模式
它們是MVC中的C
它們管理着“整個屏幕裏顯示的內容”
它們通常和它們的對象模型打包在一起
你的應用程序可以再各個視圖控制器之間移動
(Your application flows between view controllers)
它們管理“整個屏幕裏顯示的內容”?
它們看起來有很靈活的邊界
他們管理這各自獨立的“內容單元”
Table view controller: 表視圖控制器
Detail controller: 詳細控制器
SVC:SSL VPN Client
根視圖控制器真的可以管理“整個屏幕裏顯示的內容”麼?
window.rootViewController= RootViewController
自定義視圖控制器
- 子類的UIViewController
- 視圖控制器與視圖層關聯
- 重寫所選擇的API
- 在應用程序中添加邏輯
- 配置tango執行應用程序
Appearance callbacks
(void)viewWillAppear:
(void)viewDidAppear:
(void)viewWillDisappear:
(void)viewDidDisappear:
Rotation callbacks
(void)viewWillRotateToInterfaceOrientation:duration:
(void)viewWillAnimateRotationToInterfaceOrientation:
(void)viewDidRotateFromInterfaceOrientation:
也許在iPhone上很少要關心的屏幕旋轉問題的,但是大屏幕的iPad上就不同了,很多時候你需要關心橫豎屏。rotation callbacks 一般情況下只需要關心三個方法 :
willRotateToInterfaceOrientation:duration:在旋轉開始前,此方法會被調用;
willAnimateRotationToInterfaceOrientation:duration: 此方法的調用在旋轉動畫block的內部,也就是說在此方法中的代碼會作爲旋轉animation block的一部分;
didRotateFromInterfaceOrientation:此方法會在旋轉結束時被調用。而作爲view controller container 就要肩負起旋轉的決策以及旋轉的callbacks的傳遞的責任。
視圖控制器(基礎知識)
總結
視圖控制器僅僅只是控制器 —— 是MVC中的C
視圖控制器管理視圖層次結構 —— 而非單一的視圖
視圖控制器通常是自包含的(可重複使用)
視圖控制器連接並支持通用的iOS應用程序流
路線圖
瞭解視圖控制器容器
視圖控制器和視圖層次
視圖控制器互相連接的三種方式
設計自定義容器控制器
探討如何新增和修改API
視圖控制器
兩個層次的故事
藍色:視圖顏色
藍色箭頭:子視圖關係金色: 視圖控制器顏色
灰色箭頭:父視圖控制器關係
相對於內容的容器
層次關係
視圖控制器容器
層次關係
視圖控制器容器
層次關係
- 你應該知道些什麼?
容器控制器是負責 父/子 關係的
視圖控制器容器
API和控制器層次
API和控制器層次
Container View Controller
容器視圖控制器包含其他視圖控制器所擁有的內容。也就是說一個View Controller顯示的某部分內容屬於另一個View Controller,那麼這個View Controller就是一個Container.
iOS 5.0 開始支持Custom Container View Controller,開放了用於構建自定義Container的接口。如果你想創建一個自己的Container,那麼有一些概念還得弄清楚。Container的主要職責就是管理一個或多個Child View Controller的展示的生命週期,需要傳遞顯示以及旋轉相關的回調。
UITableViewController
很多應用程序顯示錶格數據。因此,iOS提供了一個專門用來管理表格數據的內建的UIViewController類的子類。UITableViewController 管理一個表格視圖並支持很多標準表格相關的行爲,比如選擇(selection)管理,行編輯,以及表格配置。這些額外的支持減少了你創建和初始化一個基於表格界面必須編寫的代碼總量。你還可以子類化UITableViewController來添加其它自定義行爲。Recipe Controller
食譜控制器
顯示或者旋轉的回調的觸發的源頭來自於window,一個app首先有一個主window,初始化的時候需要給這個主window指定一個rootViewController,window會將顯示相關的回調(viewWillAppear:, viewWillDisappear:, viewDidAppear:, or viewDidDisappear: )以及旋轉相關的回調(willRotateToInterfaceOrientation:duration: ,willAnimateRotationToInterfaceOrientation:duration:, didRotateFromInterfaceOrientation:)傳遞給rootViewController。rootViewController需要再將這些callbacks的調用傳遞給它的Child View Controllers。
視圖控制器容器
API和控制器層次
- 添加和刪除子控制器
(void)addChildViewController:(UIViewController *)childController;
(void)removeFromParentViewController;
- 訪問子控制器
@property(nonatomic,readonly) NSArray *childViewControllers;
- 回調
(void)willMoveToParentViewController:(UIViewController *)parent;
(void)didMoveToParentViewController:(UIViewController *)parent;
視圖控制器容器
層次關係
- 你應該知道些什麼?
容器控制器是負責 父/子 關係的
有一致和不一致的層次結構
視圖控制器容器
不一致的層次結構
UIViewControllerHierarchyInconsistencyException
爲什麼會這麼糟糕?
視圖控制器容器
層次關係
- 你應該知道些什麼?
容器控制器是負責 父/子 關係的
有一致和不一致的層次結構
這時,其實出現了回調
[self addChildViewController:note];
// Transition to note controller with a flip transition which adds
// tne note view to the window hierarchy and removes the recipe view.
[self transitionFromViewController:recipe
toViewController:note
duration:.5
options:UIViewAnimationOptionTransitionFlipFromRight
animations:nil
completion:^(BOOL finished) {
[note didMoveToParentViewController:self];
}];
viewWillAppear:
該視圖添加到 windows 的視圖層次結構之前調用
在 [vc.view layoutSubviews](if necessary)之前調用viewDidAppear:
該視圖添加到視圖層次結構之後調用
在 [vc.view layoutSubviews](if necessary)之後調用viewWillDisappear:
該視圖從 windows 的視圖層次結構移除之前調用- viewDidDisappear:
該視圖從 windows 的視圖層次結構移除之後調用
[self addChildViewController:note];
// Transition to note controller with a flip transition which adds
// tne note view to the window hierarchy and removes the recipe view.
[self transitionFromViewController:recipe
toViewController:note
duration:.5
options:UIViewAnimationOptionTransitionFlipFromRight
animations:nil
completion:^(BOOL finished) {
[note didMoveToParentViewController:self];
}];
視圖控制器容器
API和控制器層次
- 子視圖控制器之間的轉換
- (void)transitionFromViewController:(UIViewController *) fromVC
toViewController:(UIViewController *)toVC
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion;
- 佈局視圖層次結構
- (void)viewWillLayoutSubviews
- (void)viewDidLayoutSubviews
連接
流 — —打開和關閉屏幕時獲取視圖控制器
連接視圖控制器
通過container controllers(容器控制器)
通過presentation(呈現) 和 dismissal (解散)
通過直接視圖操作
Containers(容器)
- (void)pushViewController:
animated:
- (void)popViewControllerAnimated:
Presentation and dismissal
- (void) presentModalViewController:
animated:
- (void) dismissModalViewControllerAnimated:
- (void)presentViewController: (UIViewController *)vc
animated: (BOOL)animated
completion: (void (^)(void))completion;
- (void)dismissViewControllerAnimated:(BOOL)animated
completion: (void (^)(void))completion;
- (UIViewController *)parentViewController;
- (UIViewController *)presentingViewController;
視圖操作
[root.someView addSubview: vc.view]
[rootVC addChildViewController: vc]
視圖控制器容器
inception(啓動)
- 你會在什麼時候考慮創建一個自定義視圖控制器容器?
Aesthetics(考慮到美觀)
自定義應用程序流
您的應用程序直接處理視圖層次結構
inception(啓動)僅在iPad上
@protocol UISplitViewControllerDelegate
...
// Returns YES if a view controller should be hidden by
// the split view controller in a given orientation.
// (This method is only called on the leftmost view controller
// and only discriminates portrait from landscape.)
- (BOOL)splitViewController: (UISplitViewController*)svc
shouldHideViewController:(UIViewController *)vc
inOrientation:(UIInterfaceOrientation)orientation;
@end
設計一個新的應用程序流
爲修正一個食譜應用創建一個應用程序流
Container View Controller Demo
視圖控制器容器
演示亮點 — — 容器的移動
- (IBAction)flipToNote
{
if(...) {
...
[self addChildViewController:_noteController];
[self transitionFromViewController:_contentController
toViewController:_noteController duration:.5
options:UIViewAnimationOptionTransitionFlipFromRight
animations:nil
completion:^(BOOL finished) {
_flipNoteButton.title = @"Hide Note";
_flipNoteButton.action = @selector(flipFromNote);
[_noteController didMoveToParentViewController:self];
}];
}
}
- (IBAction)flipFromNote
{
if(_isNoteBeingShown) {
[_noteController willMoveToParentViewController:nil];
[self transitionFromViewController:_noteController
toViewController:_contentController duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:nil
completion:^(BOOL finished) {
_flipNoteButton.title = @"Show Note";
_flipNoteButton.action = @selector(flipToNote);
[_noteController removeFromParentViewController];
_isNoteBeingShown = NO;
}];
}
}
Moving in and out of containers
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if(![self isMovingToParentViewController]) {
[[self parentViewController] updateSelectionForListOfContentIdentifiersIfNecessary];
}
}
inception(啓動)
- (BOOL)isMovingToParentViewController; // Used in appearance callbacks
- (BOOL)isMovingFromParentViewController; // Used in disappearance callbacks
- (BOOL)isBeingPresented;
- (BOOL)isBeingDismissed;
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers;
- (IBAction)flipToNote
{
if(...) {
...
[self addChildViewController:_noteController];
[_noteController viewWillAppear: YES];
// Some fancy animation that culminates in the view swap
// E.g [[_contentController.view superview] addSubview:_noteController.view];
...
// Finally this is usually called in a completion handler
// after the animation completes
[_noteController viewDidAppear: YES];
[_noteController didMoveToParentViewController:self];
}
}
容器視圖控制器示例
爲修正一個食譜應用創建一個應用程序流
演示亮點 — — 定義演示文稿上下文
- (IBAction)emailContent
{
UIViewController *presenter= _isNoteBeingShown ? _noteController:
_contentController;
...
mailController.modalPresentationStyle = UIModalPresentationCurrentContext;
if(_contentController && [MFMailComposeViewController canSendMail]) {
...
data = [_contentProvider dataForContentIdentifier:self.contentControllerIdentifier
mimeType:&mimeType];
note = [_contentProvider noteForContentIdentifier:self.contentControllerIdentifier];
...
[presenter presentViewController:mailController
animated:YES
completion:^{[mailController release];}];
}
}
mc.modalPresentationStyle = UIModalPresentationCurrentContext;
[rb presentViewController:mailController
animated:YES
completion:^{...}];
mc.modalPresentationStyle = UIModalPresentationCurrentContext;
[note presentViewController:mailController
animated:YES
completion:^{...}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
self.definesPresentationContext = YES;
...
}
@property(nonatomic,assign) BOOL definesPresentationContext;
// A controller that defines the presentation context can also
// specify the modal transition style if this property is true.
@property(nonatomic,assign) BOOL providesPresentationContextTransitionStyle;
視圖控制器容器
總結
儘可能利用現有的容器
視圖控制器可以管理多個視圖
不是每個視圖都需要一個視圖控制器當需要時,創建自定義視圖控制器容器
定義新的應用程序或實現
而不是直接視圖操作(這將創造出具有前瞻性的應用)該 API 很簡單
但理解你的層次結構
UIPageViewController
導航與視圖之間的頁面捲曲過渡
UIPageViewController
一個容器視圖控制器
管理子視圖控制器的當前內容
展示一個已準備的應用程序流程
Initialization(初始化)
- initWithTransitionStyle:
navigationOrientation:
options:
UIPageViewController *myPVC = [[UIPageViewController alloc]
initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInteger:UIPageViewControllerSpineLocationMid],
UIPageViewControllerOptionSpineLocationKey]]
初始視圖控制器
- setViewControllers:
direction:
animated:
completion:
[myPVC setViewControllers:[NSArray arrayWithObjects:firstVC, secondVC, nil]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
編程導航
[myPVC setViewControllers:[NSArray arrayWithObjects:thirdVC, fourthVC, nil]
direction:UIPageViewControllerNavigationDirectionForward
animated: NO
completion:nil]
YES
^(BOOL finished) {
NSLog(@"Page curl completed.");
}];
[myPVC setViewControllers:[NSArray arrayWithObjects:thirdVC, fourthVC, nil]
direction:UIPageViewControllerNavigationDirectionForward
animated:
completion:
YES
^(BOOL finished) {
NSLog(@"Page curl completed.");
}];
交互-用戶驅動導航
Demo 總結
接下來我們知道
初始化頁面視圖控制器與過渡樣式,導航定位和任何選項 (spine location)
設置初始視圖控制器 (和驅動編程導航)
通過設置數據源允許用戶驅動導航我們從中學到什麼:
通過放置手勢識別器自定義手勢區
在旋轉和拖拽過程中改變spine location- 理解內容和容器視圖控制器之間的區別
使用自定義視圖控制器容器…
。。。定義新的應用程序或looks
。。。代替直接視圖操作儘可能利用現有的容器
UINavigationController, UITabBarController, UISplitViewController, etc.
新的容器視圖控制器, UIPageViewController