文章目錄
- 前言
- push和pop
- present和dismiss
- 基本方法
- 屬性說明
- 常見的用法
- 運行演示
- push和present區別
前言
在之前的學習中,我們發現iOS有兩種用于推出新界面的常用方法,分別是push和present,但是二者存在很多區別
present只能返回自己的上一級視圖,而push的所有視圖都是由視圖棧控制,可以返回上一級,也可以返回根視圖或者其他視圖
在iOS13之后,我們present推出的頁面不會完全覆蓋之前的界面,上面會留有一條縫隙,并且我們可以通過向下拖動直接關閉當前的頁面
push和pop
push和pop用于在導航控制器UINavigationController中,對視圖控制器的添加與移除
原理是導航控制器會維護一個棧,在經過push后,新的view會被壓到棧頂,所以在刪除或者添加時要先對棧頂的進行操作
對根視圖進行pop時是一個無效的操作,除非用setViewControllers: 直接替換整個棧或者把整個 UINavigationController dismiss 掉。
-
pushViewController: animated:
就是把一個新的視圖控制器壓入棧頂,導航控制器會顯示這個新的控制器。
(相當于進棧 → 顯示新頁面)
-
popViewControllerAnimated:
就是把當前棧頂的控制器移除,導航控制器會顯示下一個棧頂(之前的那個控制器)。
(相當于出棧 → 回到上一個頁面)
與此同時,除了對單個的push和pop,你也可以用以下兩個方法
- popToRootViewControllerAnimated: 一次性回到根控制器
- popToViewController:animated: 一次性回到棧中某個已存在的控制器
若你直接pop到根視圖或者下面的某個指定視圖控制器,會將其上面的全部釋放
部分代碼演示:
首先,我們要先設置一個根視圖控制器
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {self.window.frame = [UIScreen mainScreen].bounds;VCRoot* root = [[VCRoot alloc] init];UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController: root];self.window.rootViewController = nav;[self.window makeKeyAndVisible];
}
之后我們再在根視圖上添加跳轉函數及對根視圖的初始化
- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.self.title = @"First";self.navigationItem.title = @"根視圖";self.view.backgroundColor = [UIColor whiteColor];self.navigationController.navigationBar.barStyle = UIBarStyleDefault;UIBarButtonItem* next = [[UIBarButtonItem alloc] initWithTitle: @"下一級界面" style: UIBarButtonItemStylePlain target: self action: @selector(pressNext)];self.navigationItem.rightBarButtonItem = next;
}- (void)pressNext {VCSecond* vcsecond = [[VCSecond alloc] init];[self.navigationController pushViewController: vcsecond animated: YES];
}
后面幾個視圖也如法炮制,并在最后一個視圖設置跳轉到根視圖的方法
運行結果:
present和dismiss
present和dismiss分別用來從當前控制器模態彈出視圖控制器和關閉模態視圖控制器,兩個方法分別為
模態彈出的意思是,一個新的頁面(控制器)以覆蓋的形式展示在當前頁面之上,用戶必須 處理完 / 關閉這個頁面(通過 dismiss),才能回到之前的頁面
基本方法
-
presentViewController:
使用其彈出一個視圖之后,當前控制器會持有一個presentedViewController,被展示的控制器(B)會有一個 presentingViewController 指向 A。
-
dismissViewController:
默認只能 dismiss 自己或自己上層的控制器,不能直接跨級 dismiss。
屬性說明
這里提到了兩個之前未接觸的屬性,presentedViewController和presentingViewController
-
presentedViewController:
當前控制器所呈現的控制器 A.presentedViewController = B
-
presentingViewController:
當前控制器的呈現者 B.presentingViewController = A
常見的用法
- A -> B的跳轉
SecondViewController *second = [[SecondViewController alloc] init];
[self presentViewController:second animated:YES completion:nil];
所產生的效果:
- A present出 B
- A.presentedViewController = B
- B.presentingViewController = A
- B -> A的返回
[self dismissViewControllerAnimated:YES completion:nil];
即收起b返回a
- 多級返回:D -> A
假設層級是:A -> B -> C -> D如果想直接從 D 返回到 A,可以找到最頂層的 presentingViewController:
UIViewController *rootVC = self.presentingViewController;
while (rootVC.presentingViewController) {rootVC = rootVC.presentingViewController;
}
[rootVC dismissViewControllerAnimated:YES completion:nil];
- 多級返回:D -> B
若想從D返回到B,我們可以走兩次presenting,即一次一次退出:
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
亦或者我們可以先找到指定類再 dismiss
UIViewController *rootVC = self.presentingViewController;
while (![rootVC isKindOfClass:[SecondViewController class]]) {rootVC = rootVC.presentingViewController;
}
[rootVC dismissViewControllerAnimated:YES completion:nil];
這樣我們可以指定返回到某個具體頁面
運行演示
push和present區別
- push必須嵌套于導航控制器,且原理是把新控制器壓入導航棧,主要用于一層一層的層級導航,且自動有返回按鈕方便返回
- present可在任何控制器上使用,且不會完全覆蓋,返回時除了下滑必須手動添加按鈕進行關閉,主要適用于獨立的彈出提示等放面