1. 程式人生 > >iOS多控制器-檢視切換.

iOS多控制器-檢視切換.

多控制器-檢視切換.

1.概述.

在iOS開發中,檢視的切換是很頻繁的,常用的檢視切換有三種:

  1. UITabBarController
    • 以平行的方式管理檢視,各個檢視之間關係不大;每個加入的檢視都會進行初始化,不論當前顯不顯示在介面上.所以相對比較佔記憶體.
  2. UINavigationController (PUSH)
    • 以棧的方式管理檢視,各個檢視的切換就是壓棧和出棧操作,出棧後的檢視即被銷燬.
  3. modal模態視窗.
    • 以模態視窗的形式管理檢視,當前檢視關閉前其他檢視上的內容無法操作。(遮蓋)
  4. 自定義控制器切換.

2. UINavigationController

2.1 簡介

導航控制器,用來組織有層次關係的檢視,在UINavigationController中子控制器以棧(先進後出)的形式儲存,只有在棧頂的控制器能夠顯示在介面中,一旦一個子控制器出棧則會被銷燬;它必須有指定一個根控制器rootViewController才能建立,而且這個根控制器不會像其他子控制器一樣被銷燬,剛建立時,rootViewController即是棧底也是棧頂控制器;點選下一頁就是控制器進棧,點選返回就是出棧(銷燬).

導航條:

導航條的設定是根據棧頂控制器的navigationItem屬性設定,導航條子控制元件是系統決定位置.高度44;

基本使用:

  1. 建立導航控制器:需要先建立其root控制器. [[UINavigationController alloc] initWithRootViewController: rootController]
    之後把導航控制器設為UIWindow的root控制器.
  2. 新增子控制器,子控制器表現兩種儲存形式:viewControllers 和 childViewController陣列.新增方式:

    • nav.viewControllers = @[vc,vc2];
    • [nav addChildViewController:vc];
    • initWithRootViewController:vc;
    • [nav pushViewController:vc animated:YES]; (預設封裝了新增子控制元件方法)
  3. 跳轉-進棧
    [self.navigationController pushViewController:vc animated:YES];

  4. 主動出棧-手動跳轉
    a. 返回上一個(棧頂出棧)popViewControllerAnimated: ;
    b. 返回根控制器(出棧至棧底)popToRootViewControllerAnimated: ;
    c. 返回指定控制器(根據儲存形式下標).popToViewController: .
2.2 使用範例:

AppDelegate.m中:

//建立視窗
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

//1. 建立導航控制器的根控制器
ViewController *vc = [[ViewController alloc] init];
vc.view.backgroundColor = [UIColor redColor];

//2. 建立導航控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
nav.view.backgroundColor = [UIColor blueColor];

     //引申可以在這裡設定全域性導航條風格和顏色
[[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1]];
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

//3.把導航控制器設為視窗根控制器
self.window.rootViewController = nav;
//把視窗設為主視窗並顯示
[self.window makeKeyAndVisible];

在子控制器ViewController中

//對於當前子檢視來說其父控制器就是器導航控制器,可以獲取.
//self.navigationController == self.parentViewController;

//在子檢視中,可以通過navigationItem用於訪問和設定導航條資訊. (正在顯示的導航條由棧頂即當前顯示的子控制器來設定.)
self.navigationItem.title = @"haha";  (可以用self.title 代替 是系統內部封裝的快速設定標題方法.)

//例:設定導航條左側按鈕   
//方式一: 新建一個 UIButton *button = [[UIBarButtonItem alloc] init];
    //給button設定圖片,title等屬性.
    //導航條上子控制元件的位置是由系統決定的, 但是尺寸是由我們自己決定的.可以設定bounds;  可以使用自適應尺寸方法省得計算. 
    [button sizeToFit];    
    //最後,根據這個button來自定義建立導航條按鈕.
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];

//方式二: 直接呼叫建立方法  -- //點選觸發呼叫addFriends方法.
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"Icon.png"] style:UIBarButtonItemStyleDone target:self action:@selector(addFriends)];

}


//建立並 跳轉下一個子檢視
-(void)addFriends{
//通過push導航到另外一個子檢視
QQViewController *qqViewController=[[QQViewController alloc]init];
[self.navigationController pushViewController:qqViewController animated:YES];
}    

//iOS 7 之後, 預設會把導航條上的按鈕的圖片渲染成藍色,可用取消自動渲染
//    image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

下一級子控制器中,如果要返回.

a. 返回上一個(棧頂出棧)popViewControllerAnimated: ;
b. 返回根控制器(出棧至棧底)popToRootViewControllerAnimated: ;
c. 返回指定控制器(根據儲存形式下標).popToViewController:  .
2.3 小結:
  • UINavigationController預設顯示一個根控制器,所以根檢視必須指定,通過根控制器導航來到下一級子檢視;
  • 子檢視中可以通過navigationController來訪問導航控制器,同時可以利用導航控制的childViewControllers來獲取當前棧中所有子檢視.(出棧的已被銷燬)
  • 導航控制器導航條由棧頂控制器設定
  • 預設情況下除了根控制器之外的其他子控制器左側都會在導航欄左側顯示返回按鈕,點選可以返回上一級檢視,同時返回按鈕title預設是上一級的標題. 可以通過backBarButtonItem修改;

3. UITabBarController

3.1 簡介

UITabBarController是蘋果專門為了利用頁籤切換檢視而設計的,包含一個UITabBar控制元件,使用者通過點選tabBar進行檢視切換.為了儘可能減少檢視之間的耦合,所有UITabBarController的子檢視的相關標題、圖示等資訊均由子檢視自己控制,UITabBarController僅僅作為一個容器存在。

結構:
和導航控制器類似:它的view用來存放UITabbar和子控制器view兩部分;
不同點:

  1. 他的導航條UITabbar在下方,高度49;
  2. 不依賴RootViewController建立;
  3. UITabbar的子控制元件UITabBarButton跟棧頂無關,只跟對應的子控制器有關.子控制元件數由子控制器數決定.自動位置是均分的,所以一般分四個,典型例子微信和QQ.
  4. 導航控制器出棧會銷燬子控制器,UITabBarController不會銷燬控制器.
3.2 一般步驟
  1. 新建初始化UITabbarController;並設為視窗的root控制器.
  2. 設定UITabBarButton樣式:
    • 由對應子控制器的UITabBarItem設定.
    • 包含:title標題,image圖示,selectedImage選中狀態圖示,badgeValue右上角內容通知個數;iOS7之後系統自動渲染.
  3. 新增 子控制器.
  4. 跳轉:點選UITabBarButton自動跳轉.
3.3 小結
  • UITabBarController會一次性初始化所有子控制器,可以將檢視控制器的tabBarItem屬性設定放到init方法中設定.
  • 每個檢視控制器都有一個tabBarController屬性,通過它可以訪問所在的父UITabBarController.
  • 每個檢視控制器都有一個tabBarItem屬性,通過它控制檢視在UITabBarController的tabBar中的顯示資訊。

4. 模態視窗.

4.1 簡介

模態視窗只是檢視控制器的顯示的一種方式.不依賴與控制器容器;通常用於顯示較獨立的內容,在模態視窗顯示的時,其他檢視的內容無法進行操作.

4.2 一般使用
  • 使用起來比較容易,一般的檢視控制器只要呼叫- (void)presentViewController:(UIViewController *)viewController animated: (BOOL)flag completion:(void (^)(void))completion方法, 那麼引數中的viewController就會以模態視窗的形式展現; 而此檢視控制器再呼叫—(void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion就會關閉模態視窗,回到原檢視.
    注意:modal出誰,誰才可以使用dismiss;

    一般為了操作方便,會給模態視窗設定導航條,兩種方式:
    第一種:手動建立

    //建立一個導航欄
    UINavigationBar *navigationBar=[[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 44+20)];
    //navigationBar.tintColor=[UIColor whiteColor];
    [self.view addSubview:navigationBar];
    //建立導航控制元件內容
    UINavigationItem *navigationItem=[[UINavigationItem alloc]initWithTitle:@”Web Chat”];

    //左側新增登入按鈕
    _loginButton=[[UIBarButtonItem alloc]initWithTitle:@”登入” style:UIBarButtonItemStyleDone target:self action:@selector(login)];

    navigationItem.leftBarButtonItem=_loginButton;

    //新增內容到導航欄
    [navigationBar pushNavigationItem:navigationItem animated:NO];

第二種: 把控制器包裝成導航控制器.這是給控制器新增導航條的最快方法.

4.主流框架

導航控制器和UITabBarController結合.一般由UITabBarButton做父控制元件:
原因:

  • 由於導航控制器的導航條由棧頂控制器決定,如果導航做父控制器,那麼在UITabBarController的子控制元件間切換時,上方導航始終不變.而UITableBarController的bar由各子控制器決定自己的.
  • UITabBarController的子控制器數目由於均分UITabBar位置,數目有限制不超過五個.

5.多控制器的資料傳遞

5.1 segue跳轉原理.
  • 如果segue的type是push: 取得sourceViewController所在的UINavigationViewController, 再呼叫push方法壓入棧中完成跳轉.
  • 如果segue的type是modal:呼叫sourceViewController的 presentViewController方法,將destinationViewController展示出來.

介面跳轉:
執行[self performSegueWithIdentifier:@”id” sender:nil];時

  1. 執行segue.
    1. 根據Identifier去storyboard找對應的線,找到後,建立segue物件;
    2. 設定segue的sourceViewController(來源控制器),此時的self;
    3. 建立destinationViewController(目標),並設定器屬性;
    4. 最後跳轉前,會執行prepareForSegue方法,做跳轉前的準備工作(一般是引數傳值).;
    5. 最後系統就會自動呼叫self perform方法,進行跳轉;
  2. perform底層
    1. 拿到來源控制器的導航控制器
    2. 進行 push 操作, push 到目標控制器
    3. 由 segue 拿到目標控制器
1.順傳:

源控制器把資料->目標控制器設定的屬性接收.程式碼示例:

在sourceViewController中;
// 判斷賬號密碼
    if ([self.accountField.text isEqualToString: @"hm"] && [self.pwdField.text isEqualToString: @"123"]) { // 賬號密碼都正確
        // 跳轉介面
        [self performSegueWithIdentifier:@"login2Contact" sender:nil];

//跳轉前會執行prepareForSegue方法 並傳入sugue 和sender :可通過傳入的segue獲取來源和目標控制器; sender是之前performSegueWithIdentifier傳入的sender;

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// 獲取目標控制器.
UIViewController *vc = segue.destinationViewController;

// 順傳: 上一個控制器(來源控制器)把資料傳遞給下一個控制器(目標控制器)
vc.navigationItem.title = self.accountField.text; 
}//可以傳遞模型資料.在目標控制器中設定屬性接收即可.
2.逆傳:

原理是:來源控制器把自己->目標控制器,再在目標中設定來源控制器的屬性. 但是:這種耦合性太高,所以引入代理模式解耦;

代理=>有限制的物件間關聯關係,通過把兩個關聯物件用協議束縛起來,達到解耦目的.

  1. 來源控制器 做 目標控制器 的代理,我們在目標控制器中定義協議,宣告方法(把自己和資料作為引數)一般只傳資料就夠了,傳自己是蘋果代理程式設計習慣. 來源控制器 遵守協議,實現方法.
  2. 通過segue在目標中獲取來源控制器.呼叫此方法,傳入資料.
  3. 注意:呼叫前先做個判斷(是否代理實現了方法) respondsToSelect;
  4. 注意:如果一個控制器segue了多個控制器,那麼用segue獲取目標控制器需要判斷一下- isKindOfClass:
  5. 注意點:控制器順傳通常不能重寫模型資料的set方法給子控制元件賦值,應為傳值是在跳轉之前傳得,而此時控制器的view還沒有載入,也就意味著子控制元件還沒建立. 所以把值傳過去後,在viewdidload中設定子控制元件屬性.
  6. 其他逆傳值方式:
    • block逆傳值:捕獲自動變數的匿名函式指標.
    • 通知機制
    • 通過儲存
    • 通過AppDelegate定義全域性變數(或者使用UIApplication、定義一個單例類等)

iOS主要使用代理來逆傳值,程式碼如下:

目標控制器中:

// .h中 定義協議 
@protocol HMAddViewControllerDelegate <NSObject>
// 宣告方法.
- (void)addViewControllerWith:(HMAddViewController *)addVc didClickButton:(HMContact *)contact;    //contact是模型資料
// 新增delegate
@property (nonatomic, weak) id<HMAddViewControllerDelegate> delegate;

//.m中
// 通知代理: 聯絡人控制器
if ([self.delegate respondsToSelector:@selector(addViewControllerWith:didClickButton:)]) {
    [self.delegate addViewControllerWith:self didClickButton:contact];
}

來源控制器中.

//1. 在prepareForSegue方法中獲取到目標控制器 .  讓自己成為其代理
    // 獲取目標控制器(新增控制器)
HMAddViewController *addVc = segue.destinationViewController;
    // 傳遞聯絡人控制器: 給目標控制器的 contactVc 屬性賦值
addVc.delegate = self;

//2. 實現代理方法
- (void)addViewControllerWith:(HMAddViewController *)addVc didClickButton:(HMContact *)contact {
    // 儲存聯絡人模型
[self.contacts addObject:contact];

}

自定義多控制器切換.

某些時候,系統的導航控制器和UITabBarController不能滿足專案需求, 需要我們自定義跳轉效果.

1. 實現原理.

在主控制器上建立新控制器,並讓新控制器View覆蓋主View即可;

2. 細節與步驟.
  • 建立新控制器,並將所有新控制器 變為主控制器的子控制器.
[self addChildViewController:[[HMOneViewController alloc] init]];
[self addChildViewController:[[HMTwoViewController alloc] init]];
  • 在主控制器中使用屬性記錄新控制器.(由於前面add,所以可以使用weak)
@property (nonatomic, weak) UIViewController *showingChildVc;
  • 提供切換控制器方法, 為了減少程式碼冗餘, 使用下標,來訪問 childViewcontrollers陣列.
-(void)switchVC:(int)index { //即將要顯示的子控制器索引
    //1. 移除當前正在顯示的其他子控制器view 
    [self.showingChildVc.view removeFromSuperview];
    //2. 新增index位置對應控制器的view,並設定frame,
    UIViewController *newVc = self.childViewcontrollers[index];
    newVc.view.frame = CGRectMake(0, 44, self.view.frame.size.width, self.view.frame.size.height - 44);
    [self.view addSuperview:newVc.view];
    //3. 記錄要顯示的子控制器
    self.showingChildVc = newVc; 
}

注意: 一定要建立需切換控制器的父子關係, 否則某些系統事件 子控制器無法接收並響應. 子控制器也無法獲取父控制器的tabbar或導航控制器傳送跳轉訊息.

介面切換的方式和選擇:
  • 業務邏輯簡單: 一個控制器多個View 切換
  • 業務邏輯複雜時 使用多個控制器多個view,建立父子關係切換.(相當於1 給view配控制器,方便管理)

自定義的轉場動畫.

  1. 自定義動畫程式碼因新增在切換控制器的方法中.
  2. 執行過渡動畫的view要經歷移除和新增事件.
  3. 動畫執行呼叫CATransition類, 核心動畫是新增在View的圖層上的.
- (void)switchVc:(int)index
{
    UIViewController *newVc = self.childViewControllers[index];
    // 如果index對應的子控制器正在顯示,就直接返回
    if (newVc == self.showingChildVc) return;

    // 0.儲存新舊控制器的索引
    NSUInteger newIndex = index;
    NSUInteger oldIndex = [self.childViewControllers indexOfObject:self.showingChildVc];

    // 1.移除其它控制器的view
    [self.showingChildVc.view removeFromSuperview];

    // 2.新增index位置對應控制器的view
    newVc.view.frame = self.contentView.bounds;
    [self.contentView addSubview:newVc.view];
    self.showingChildVc = newVc;

    // 3.執行動畫
    if (oldIndex == NSNotFound) return;
    CATransition *animation = [CATransition animation];
    animation.type = @"cube";
    if (newIndex > oldIndex) {
        animation.subtype = kCATransitionFromRight;
    } else {
        animation.subtype = kCATransitionFromLeft;
    }
    animation.duration = 1.0;
    [self.contentView.layer addAnimation:animation forKey:nil];

    //3. 可使用UIView封裝的動畫 . 進行左右轉場.
    // 動畫
    /*
    [UIView animateWithDuration:0.5 animations:^{
        CGRect oldFrame = self.showingChildVc.view.frame;
        oldFrame.origin.x = - self.view.frame.size.width;
        self.showingChildVc.view.frame = oldFrame;

        newVc.view.frame = self.contentView.bounds;
    }completion:^(BOOL finished) {
        [self.showingChildVc.view removeFromSuperview];
        self.showingChildVc = newVc;
    }];
    */
}

相關推薦

iOS控制器-檢視切換.

多控制器-檢視切換. 1.概述. 在iOS開發中,檢視的切換是很頻繁的,常用的檢視切換有三種: UITabBarController 以平行的方式管理檢視,各個檢視之間關係不大;每個加入的檢視都會進行初始化,不論當前顯不顯示在介面上.所以相對比較佔

3.1 使用UIScrollView展示檢視控制器 [原創iOS開發-Xcode教程]

1. 本節課將為您演示多檢視控制器的使用。首先在歡迎視窗中,點選[建立一個新專案]選項,建立一個新的專案。 2. 選擇建立一個簡單的單檢視應用。 3. 點選下一步按鈕,進入下一步設定頁面。 4. 在產品名稱輸入框內,點選輸入產品的名稱。 5. 保持其它引數不變,點選下一步按鈕

IOS初學-導航檢視控制器的使用

檢視控制器的跳轉方式。入棧和出棧 首先需要建立兩個檢視控制器 在FirstSubViewController中修改程式碼 //導航檢視控制器的使用     func test1()  {         se

Laravel配置控制器切換個數據庫(或任意切換資料庫)

1. 知識點:     Laravel預設資料庫是取.env和datebase.php中mysql填寫的資料庫。     如果需要切換多個數據庫,就需要填寫新的資料庫配置。     新的資料庫不需要.env檔案依賴。 &

iOS開發——檢視切換——UITabBarController——UINavigationController——模態(Model)

檢視切換原理: 1.UITabBarController:以平行的方式管理檢視,各個檢視之間的關係並不大,每個加入到UITabBarController的檢視都會進行初始化(只加載當前顯示的viewcontroller其他的只做初始化)即使當前不顯示在介面上,相對比較佔用記

控制器切換(帶滑動動畫)

主控制器 ,管理控制器 .h檔案 //巨集 #define kScreenWidth [UIScreen mainScreen].bounds.size.width #define kScreen

IOS學習之Tab Bar的使用和檢視切換

在ios的程式中,Tab Bar的使用率很高,幾個檢視需要切換的時候,就用到tabbar。 今天的程式實現的效果是這樣的,底部有幾個tab Item,對應的有幾個檢視,切換tab Item,切換到對應的檢視。 實現效果如下: 為了更好理解使用用tabbar和切換檢視,我們建立一個Empty Applic

iOS 檢視切換問題 popViewControllerAnimated 檢視重新整理問題

//在開發中,我們常用到的推出檢視的方法常用的有以下四種,配套使用,推出與返回,前兩種推出,附帶導航檢視控制器,後兩者不帶。後兩者屬於模態檢視控制器,需要注意的是,popViewControlle

iOS新增子檢視控制器

先編譯幾個子檢視控制器 //*子檢視控制器*/ @property (nonatomic, strong) tableVC *firstVC; @property (nonatomic, strong) ViewController1 *secondVC; @p

iOS storyboard 個子檢視均勻排列

好久沒寫部落格了, 平時大多看別人的部落格, 總感覺不好意思! 今天有點時間就寫一篇. 之前碰到一個問題, 用storyboard佈局UI, 多個子檢視均勻排列, 在網上找了好久解決方法,效果不好,  要不不能實現, 要不特別麻煩(還不如直接用程式碼搞定呢). 先說一下要求

IOS】分隔檢視控制器 (UISplitViewController)

轉自:http://www.cnblogs.com/wayne23/p/3596814.html 這種控制器只能用於iPad,它可以在iPad螢幕中顯示兩個不同的場景:在橫向模式下,左邊顯示一個表,供使用者選擇;使用者選擇表中的元素後,詳細檢視將顯示該元素的詳細資訊。如

iOS 模態檢視檢視之間的切換

一、檢視之間的簡單切換。   檢視之間的切換實質是檢視控制器之間的切換,因為試圖控制器(UIViewController)上面都有檢視(view),試圖控制器切換了,檢視自然就實現了切換。   新建一個工程,建立兩個類FirstViewController和SecondViewController,它

ios開發之檢視控制器(UIViewController)-- 詳解

由於本人也是初學ios開發,下面分享一下本人在自學中關於檢視控制器(UIViewController)的多種建立方法的總結(詳解)。 控制器的建立方式 注意: 以下程式碼都是在(Xcode 6.

iOS----在子檢視中獲取父檢視控制器

在實際專案當中,我們經常會遇到需要在一個父類為UIView的子檢視上進行POP或是PUSH操作,但該子檢視是不能用POP或PUSH的,這時候我們就可以根據該子檢視獲取到父檢視的控制器,從而進行POP或P

iOS 關於UIView的userInteractionEnabled屬性(檢視到點選事件)

如果父檢視為ParentView包含一個Button,如果再ParentView上新增子檢視ChildView,且ChildView蓋住了Button,那麼Button就得到不響應了,為了讓Button響應,可以設定C

iOS詳細解析檢視控制器的正向和逆向傳值

本文主要介紹在不同的檢視控制器之間進行傳值,分為兩種傳值方式,正向傳值比較容易,逆向傳值相對於正向來說麻煩一點,需要使用代理或者是block 一、正向傳值 正向傳值只需要在第一個檢視控制器中“拿到”第

ios 簡單的國語言切換,語言切換功能

App Store 中很多流行的應用程式有多種語言版本。雖然這些應用程式可能因為很多因素而變得流行,但是具有多種本地化版本,肯定是其中一個因素。越多的人可以理解並使用您的應用程式,潛在的買家也就越多。 若要讓您的應用程式擁有多個語言版本,必須先將它國際化,然後將它本地化。國

ios線程操作(四)—— GCD核心概念

indent img 操作 fort 16px 2.0 b2c 有一種 read GCD全稱Grand Central Dispatch。可譯為“大派發中樞調度器”,以純C語言寫成,提供了很多很強大的函數。GCD是蘋果公司為多核的並行運算提出的解決方式,它能夠自己主

個倒計時切換 開始和結束

move 顯示 ont tin call () doc loop script /* * @Author: Mark * @Date: 2015-08-06 13:54:01 * @Last Modified by: Mark * @Last Modified

ios導航控制器UINavigationController,控制器a跳轉(push)到b後,b跳轉(push)到c,但c後退(pop)進入a

data- object tracking not another target eas com targe 參考:StackOverflow ios導航控制器UINavigationController,控制器a跳轉(push)到b後,b跳轉(push)到c。但c後退