當我們在view controller A中模態顯示view controller B的時候,A就充當presenting view controller(彈出VC),而B就是presented view controller(被彈出VC)。官方文檔建議這兩者之間通過delegate實現交互,在被彈出的VC中定義delegate,然后在彈出VC中實現該代理,這樣就可以比較方便的實現兩者之間的交互。
模態風格:ModalTransitionStyle
UIModalTransitionStyleCoverVertical = 0, //垂直變化風格(默認)
UIModalTransitionStyleFlipHorizontal, //水平旋轉風格
UIModalTransitionStyleCrossDissolve, //閃換風格
UIModalTransitionStylePartialCurl, //上下翻書風格
1、以模態窗口的形式管理視圖,當前視圖關閉前其他視圖上的內容無法操作。
@property(nonatomic,readonly) UIViewController *presentedViewController ;//當前控制器模態出的窗口.
@property(nonatomic,readonly) UIViewController *presentingViewController;//模態出當前控制器的窗口
3、處理模態窗口(主要的方法)
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion);//顯示想要顯示的模態窗口
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion);//關閉當前顯示的模態窗口
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id) //當前控制器模態另一個窗口並傳輸數據時調用的方法
4、用模態窗口的方式實現視圖的切換,即可以在stroybord中通過modal連接的方式將幾個UIController連接后去通過按鈕事件實現切換,也可以純代碼將storyboard中的幾個UIController連接后通過按鈕事件實現切換。
5、模態窗口一般采用設置代理或者通知的方式進行反向傳輸數據。
設置代理協議或者創建通知中心都是由發送消息者完成的,由接受者設置代理或者注冊通知。
通知方式:
a.有一個(單例)通知中心,負責管理iOS中的所有通知
b.需要獲取某種通知,必須注冊成為觀察者(訂閱)
c.不再需要取某種通知時,要取消注冊。
d.你可以向通知中心發送某種通知,通知中心會轉發給相應的觀察者(訂閱者)。
NSNotificationCenter *notification = [NSNotificationCenter defaultCenter] //創建通知中心單例對象
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject //通知中心收到接收者注冊的通知
- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;//通知中心幫助發送者發送通知
- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;//接收者接受完數據,通知中心幫助取消注冊
6、presentedViewController 可以獲取到由當前控制器調用presentModalViewController展示的子視圖的控制器。
presentingViewController 則可以獲取到展示當前視圖的父級(上一級)視圖的控制器。
----------------------------------------------------------------------------------------------------------------------------------------------------------
舉例:兩個視圖切換(FirstViewController、SecondViewController),模態窗口,並輸出數據
類關聯:
SecondViewController FirstViewController
當在storyboard中直接通過modal方式將控制器連接后,需要將storyboard中Segue的屬性identifier設置為modal,以便於當前控制器模態出另一個控制器的模態窗口和傳輸數據。
第一步:拖出兩個視圖控制器到storyboard中,並已modal方式連接
第二步:設置storyboard中的segue的屬性identifier標識符
第三步:在FirstViewController控制器中模態出窗口並只進行正向傳輸數據
第四步:在SecondViewController中關閉被模態窗口,並接受數據
當storyboard中的控制器沒有通過modal方式直接連接時,可以通過代碼來連接,需要將storyboard中要被模態出窗口的控制器的identify的storyboardID設置一個標識。然后,首先創建要被模態顯示的控制器,即根據storyboard對象根據標識來加載要被模態窗口的控制器,最后進行模態窗口和傳輸數據。用這種方式傳輸數據時,如果是兩個以上的控制實現視圖切換,由於控制器耦合性太強,會出現錯錯誤,不建議使用。而是通過設置代理來實現數據的傳輸,即在被模態窗口的控制器中設置協議和代理,在模態窗口的控制器中實現代理的方法即可,大大降低了控制器中間的耦合性。
《1》切換視圖,並不通過代理實現數據正向和反向傳輸
第一步:拖出兩個視圖控制器到storyboard中,未連接
第二步:將storyboard中要被模態出窗口的控制器SecondViewController的identify的storyboardID設置一個標識
第三步:在FirstViewController控制器中模態出窗口,並正向傳遞數據
1 #import "ViewController.h" 2 #import "SecondViewController.h" 3 @interface ViewController () 4 @property (weak, nonatomic) IBOutlet UITextField *TextField; 5 6 @end 7 8 @implementation ViewController 9 -(void)setTextWithBackInfo:(NSString *)info 10 { 11 self.TextField.text = info; 12 } 13 - (void)viewDidLoad { 14 [super viewDidLoad]; 15 } 16 //純代碼創建模態顯示 17 - (IBAction)forwardClicked:(UIButton *)sender 18 { 19 //首先創建模態顯示的控制器 20 //從storyboard中加載控制器 21 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; 22 23 //匹配storyboard的標識符 24 SecondViewController *secondVC = [storyboard instantiateViewControllerWithIdentifier:@"Second"]; 25 26 //正向傳數據 27 secondVC.info = self.TextField.text; 28 29 //顯示模態窗口 30 [self presentViewController:secondVC animated:YES completion:nil]; 31 } 32 33 @end
第四步:在SecondViewController中關閉被模態出的窗口,並反向傳輸數據
《2》切換視圖,通過代理實現數據正向和反向傳輸
主要代碼如下:
FirstViewController控制器中的代碼:
1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UIViewController 4 5 -(void)setTextWithBackInfo:(NSString *)info; 6 @end
1 #import "ViewController.h" 2 #import "SecondViewController.h" 3 @interface ViewController ()<SecondViewControllerDelegate> 4 @property (weak, nonatomic) IBOutlet UITextField *TextField; 5 6 @end 7 8 @implementation ViewController 9 -(void)setTextWithBackInfo:(NSString *)info 10 { 11 self.TextField.text = info; 12 } 13 - (void)viewDidLoad { 14 [super viewDidLoad]; 15 } 16 //純代碼創建模態顯示 17 - (IBAction)forwardClicked:(UIButton *)sender 18 { 19 //首先創建模態顯示的控制器 20 //從storyboard中加載控制器 21 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; 22 23 //匹配storyboard的標識符 24 SecondViewController *secondVC = [storyboard instantiateViewControllerWithIdentifier:@"Second"]; 25 26 //正向傳數據 27 secondVC.info = self.TextField.text; 28 29 //為了接受反向數據,將自己設置為模態窗口的代理,很好的降低了模態窗口的耦合性 30 secondVC.delegate = self; 31 32 //顯示模態窗口 33 [self presentViewController:secondVC animated:YES completion:nil]; 34 } 35 36 #pragma mark -SecondViewController的代理方法 37 //通過代理接受模態窗口反向傳回的數據 38 -(void)SecondVC:(SecondViewController *)vc didFinishedWithInfo:(NSString *)info 39 { 40 self.TextField.text = info; 41 } 42 @end
SecondViewController控制器中的代碼:
1 #import <UIKit/UIKit.h> 2 @protocol SecondViewControllerDelegate; 3 @interface SecondViewController : UIViewController 4 @property (weak, nonatomic) IBOutlet UILabel *label; 5 @property (copy,nonatomic)NSString *info; 6 //2.添加代理屬性 7 @property (weak,nonatomic)id<SecondViewControllerDelegate> delegate; 8 @end 9 10 11 //1.定義協議 12 @protocol SecondViewControllerDelegate 13 14 -(void)SecondVC:(SecondViewController*)vc didFinishedWithInfo:(NSString*)info; 15 16 @end
1 #import "SecondViewController.h" 2 3 @interface SecondViewController () 4 @property (weak, nonatomic) IBOutlet UITextField *textField; 5 @end 6 7 @implementation SecondViewController 8 - (IBAction)backButtonClicked:(UIButton *)sender 9 { 10 //self.presentedViewController 當前控制器模態出的窗口 11 //self.presentingViewController 模態出當前控制器的窗口 12 13 14 //3.通過代理反向傳數據 15 [self.delegate SecondVC:self didFinishedWithInfo:self.textField.text]; 16 17 18 //關閉模態窗口 19 [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 20 21 } 22 23 - (void)viewDidLoad { 24 [super viewDidLoad]; 25 // Do any additional setup after loading the view. 26 27 self.label.text = self.info; 28 }
最后的演示結果為: