UIKit框架(二十八) —— 一個(gè)UISplitViewController的簡單實(shí)用示例 (一)

版本記錄

版本號(hào) 時(shí)間
V1.0 2019.09.18 星期三

前言

iOS中有關(guān)視圖控件用戶能看到的都在UIKit框架里面,用戶交互也是通過UIKit進(jìn)行的。感興趣的參考上面幾篇文章。
1. UIKit框架(一) —— UIKit動(dòng)力學(xué)和移動(dòng)效果(一)
2. UIKit框架(二) —— UIKit動(dòng)力學(xué)和移動(dòng)效果(二)
3. UIKit框架(三) —— UICollectionViewCell的擴(kuò)張效果的實(shí)現(xiàn)(一)
4. UIKit框架(四) —— UICollectionViewCell的擴(kuò)張效果的實(shí)現(xiàn)(二)
5. UIKit框架(五) —— 自定義控件:可重復(fù)使用的滑塊(一)
6. UIKit框架(六) —— 自定義控件:可重復(fù)使用的滑塊(二)
7. UIKit框架(七) —— 動(dòng)態(tài)尺寸UITableViewCell的實(shí)現(xiàn)(一)
8. UIKit框架(八) —— 動(dòng)態(tài)尺寸UITableViewCell的實(shí)現(xiàn)(二)
9. UIKit框架(九) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(一)
10. UIKit框架(十) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(二)
11. UIKit框架(十一) —— UICollectionView的重用、選擇和重排序(一)
12. UIKit框架(十二) —— UICollectionView的重用、選擇和重排序(二)
13. UIKit框架(十三) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(一)
14. UIKit框架(十四) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(二)
15. UIKit框架(十五) —— 基于自定義UICollectionViewLayout布局的簡單示例(一)
16. UIKit框架(十六) —— 基于自定義UICollectionViewLayout布局的簡單示例(二)
17. UIKit框架(十七) —— 基于自定義UICollectionViewLayout布局的簡單示例(三)
18. UIKit框架(十八) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫的實(shí)現(xiàn)(一)
19. UIKit框架(十九) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫的實(shí)現(xiàn)(二)
20. UIKit框架(二十) —— 基于UILabel跑馬燈類似效果的實(shí)現(xiàn)(一)
21. UIKit框架(二十一) —— UIStackView的使用(一)
22. UIKit框架(二十二) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場(chǎng)和展示(一)
23. UIKit框架(二十三) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場(chǎng)和展示(二)
24. UIKit框架(二十四) —— 基于UICollectionViews和Drag-Drop在兩個(gè)APP間的使用示例 (一)
25. UIKit框架(二十五) —— 基于UICollectionViews和Drag-Drop在兩個(gè)APP間的使用示例 (二)
26. UIKit框架(二十六) —— UICollectionView的自定義布局 (一)
27. UIKit框架(二十七) —— UICollectionView的自定義布局 (二)

開始

今天是個(gè)特殊的日子,勿忘國恥,國人當(dāng)自強(qiáng),向抵抗侵略的將士們致敬!

首先看下主要內(nèi)容

了解如何將iOS應(yīng)用程序拆分為兩個(gè)部分,并在此UISplitViewController教程的每一側(cè)顯示視圖控制器

接著看一下寫作環(huán)境

Swift 5, iOS 13, Xcode 11

應(yīng)用程序通常需要提供拆分視圖以提供整潔的導(dǎo)航模型。 這方面的一個(gè)例子是Mail.app,它在iPad上使用左側(cè)有文件夾列表的分割視圖,然后是右側(cè)選定的郵件項(xiàng)目。 Apple為我們構(gòu)建了一個(gè)非常方便的視圖控制器,稱為UISplitViewController,它可以直接回到iPad的低端。 在這個(gè)UISplitViewController教程中,您將學(xué)習(xí)如何使用它! 此外,自iOS 8起,split view controller拆分視圖控制器可在iPadiPhone上運(yùn)行。

在本教程中,您將從頭開始創(chuàng)建一個(gè)通用應(yīng)用程序,它使用split view controller來顯示Math Ninja中的怪物列表。

您將使用拆分視圖控制器來處理導(dǎo)航和顯示。 它適用于iPhoneiPad。

單擊File ? New ? Project…,在Xcode中創(chuàng)建一個(gè)新項(xiàng)目。 選擇 iOS ? Application ? Single View App模板。

將項(xiàng)目命名為MathMonsters。 將Language保持為Swift。 將User Interface設(shè)置為Storyboard。 取消選中所有復(fù)選框。 然后單擊Next完成項(xiàng)目的創(chuàng)建。

雖然您可以使用Master-Detail App模板作為起點(diǎn),但您將從頭開始使用Single View App模板。 這將使您更好地了解UISplitViewController的工作原理。 在將來的項(xiàng)目中使用UISplitViewController時(shí),這些知識(shí)將非常有用。

是時(shí)候創(chuàng)建UI了,所以打開Main.storyboard

刪除故事板中的默認(rèn)初始View Controller Scene。 同時(shí)從項(xiàng)目導(dǎo)航器中刪除ViewController.swift,確保在詢問時(shí)選擇Move to Trash。

將拆分視圖控制器拖到空的故事板中:

這將為您的storyboard添加幾個(gè)元素:

  • Split View Controller - 拆分視圖控制器:此拆分視圖將包含應(yīng)用程序的其余部分,并且是應(yīng)用程序的根。
  • Navigation Controller - 導(dǎo)航控制器:此UINavigationController將是主視圖控制器的根視圖。 這是拆分視圖的左側(cè)窗格,當(dāng)在iPad上或在較大的iPhone(如iPhone 8 Plus)上橫向顯示時(shí)。在拆分視圖控制器中,您將看到導(dǎo)航控制器具有稱為master view controller的關(guān)系segue。 這允許您在主視圖控制器中創(chuàng)建整個(gè)導(dǎo)航層次結(jié)構(gòu),而無需影響詳細(xì)視圖控制器。
  • View Controller - 視圖控制器:這將最終顯示所有怪物的詳細(xì)信息。 如果查看拆分視圖控制器,您將看到視圖控制器具有稱為詳細(xì)視圖控制器(detail view controller)的關(guān)系segue:
  • Table View Controller:這是主UINavigationController的根視圖控制器。 它最終將顯示怪物列表。

注意:Xcode會(huì)警告您表視圖的原型單元缺少重用標(biāo)識(shí)符(reuse identifier)。 暫時(shí)不要擔(dān)心。 你很快就會(huì)解決它。

由于您從故事板中刪除了默認(rèn)的初始視圖控制器,因此您需要告訴故事板您希望拆分視圖控制器成為初始視圖控制器。

選擇Split View Controller,然后打開Attributes inspector。 選中Is Initial View Controller選項(xiàng)。

您將在分割視圖控制器的左側(cè)看到一個(gè)箭頭。 這告訴你它是這個(gè)故事板的初始視圖控制器。

在iPad模擬器上構(gòu)建并運(yùn)行應(yīng)用程序。 將模擬器旋轉(zhuǎn)到橫向。

您應(yīng)該看到一個(gè)空的拆分視圖控制器:

現(xiàn)在可以在任何iPhone模擬器上運(yùn)行它,除了一個(gè)加大尺寸的手機(jī),它足夠大,可以像iPad一樣運(yùn)行。 你會(huì)看到它開始全屏顯示細(xì)節(jié)視圖。 它還允許您點(diǎn)擊導(dǎo)航欄上的后退按鈕以彈回主視圖控制器:

在除了橫向大型PlusMax設(shè)備之外的iPhone上,分割視圖控制器將像傳統(tǒng)的master-detail應(yīng)用程序一樣,帶有導(dǎo)航控制器來回推出和彈出。這是內(nèi)置功能,開發(fā)人員只需要很少的額外配置。

您需要顯示自己的視圖控制器而不是這些默認(rèn)控制器。是時(shí)候開始創(chuàng)建它們了。


Creating Custom View Controllers

故事板具有視圖控制器層次結(jié)構(gòu)集:拆分視圖控制器,其主視圖控制器和詳細(xì)視圖控制器作為其子視圖?,F(xiàn)在,您需要實(shí)現(xiàn)代碼方面以獲取要顯示的數(shù)據(jù)。

轉(zhuǎn)到File ? New ? File…,并選擇iOS ? Source ? Cocoa Touch Class模板。將類命名為MasterViewController,并使其成為UITableViewController的子類。確保未選中Also create XIB file復(fù)選框,并將Language設(shè)置為Swift。單擊Next,然后單擊Create。

打開MasterViewController.swift

向下滾動(dòng)到numberOfSections(in:)中。刪除此方法。只返回一個(gè)部分時(shí)不需要它。

接下來,找到tableView(_:numberOfRowsInSection :)并用以下內(nèi)容替換實(shí)現(xiàn):

override func tableView(
  _ tableView: UITableView, 
  numberOfRowsInSection section: Int) 
    -> Int {
  return 10
}

最后,取消注釋tableView(_:cellForRowAt :)并將其實(shí)現(xiàn)替換為以下內(nèi)容:

override func tableView(
  _ tableView: UITableView, 
  cellForRowAt indexPath: IndexPath) 
    -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
  return cell
}

這樣,當(dāng)你稍后測(cè)試這個(gè)東西時(shí),你將看到十個(gè)空行。

打開Main.storyboard。 選擇Root View Controller并切換Identity檢查器。 將類更改為MasterViewController。

此外,您需要確保在表視圖中為原型單元格提供重用標(biāo)識(shí)符。 如果沒有,它會(huì)在故事板試圖加載時(shí)導(dǎo)致崩潰。

Master View Controller中,選擇Prototype Cell。 在Attributes inspector中,將Identifier更改為Cell。 同時(shí)將單元格Style更改為Basic。

iPadiPhone模擬器中構(gòu)建和運(yùn)行。 你會(huì)注意到雖然有十行,都標(biāo)有標(biāo)題,點(diǎn)擊一行不會(huì)做任何事情。 這是因?yàn)槟形粗付ㄔ敿?xì)視圖控制器。

現(xiàn)在,您將為細(xì)節(jié)方創(chuàng)建視圖控制器。

轉(zhuǎn)到File ? New ? File…,并選擇iOS ? Source ? Cocoa Touch Class模板。 將類命名為DetailViewController,并使其成為UIViewController的子類。 確保未選中Also create XIB file復(fù)選框,并將Language設(shè)置為Swift

單擊Next,然后單擊Create。

打開Main.storyboard并在View Controller Scene中選擇視圖控制器。 在Identity inspector中,將Class更改為DetailViewController

然后將label拖到詳細(xì)視圖控制器的中間。 使用“自動(dòng)布局”將label固定到容器的水平和垂直中心。

雙擊label將其文本更改為Hello,World!,所以當(dāng)你稍后測(cè)試它時(shí)你會(huì)知道它正在工作。

構(gòu)建并運(yùn)行。 此時(shí),您應(yīng)該看到自定義視圖控制器。

iPad上:

iPhone上:

您現(xiàn)在已經(jīng)獲得了拆分視圖的基礎(chǔ),每個(gè)位都有自定義視圖控制器。 接下來你需要添加那些討厭的怪物。


Making Your Model

接下來,您需要為要顯示的數(shù)據(jù)定義模型。 在學(xué)習(xí)拆分視圖控制器的基礎(chǔ)知識(shí)時(shí),您不希望復(fù)雜化,因此您將使用沒有數(shù)據(jù)持久性的簡單模型。

首先,創(chuàng)建一個(gè)表示要顯示的怪物的類。 轉(zhuǎn)到File ? New ? File…,選擇iOS ? Source ? Swift File模板,然后單擊Next。 將文件命名為Monster,然后單擊Create。

您將創(chuàng)建一個(gè)簡單的類,其中包含有關(guān)要顯示的每個(gè)怪物的屬性屬性。 您還將實(shí)現(xiàn)一些方法來創(chuàng)建新的怪物并訪問每個(gè)怪物武器的圖像。

用以下內(nèi)容替換Monster.swift的內(nèi)容:

import UIKit

enum Weapon {
  case blowgun, ninjaStar, fire, sword, smoke

  var image: UIImage {
    switch self {
    case .blowgun:
      return UIImage(named: "blowgun.png")!
    case .fire:
      return UIImage(named: "fire.png")!
    case .ninjaStar:
      return UIImage(named: "ninjastar.png")!
    case .smoke:
      return UIImage(named: "smoke.png")!
    case .sword:
      return UIImage(named: "sword.png")!
    }
  }
}

class Monster {
  let name: String
  let description: String
  let iconName: String
  let weapon: Weapon

  init(name: String, description: String, iconName: String, weapon: Weapon) {
    self.name = name
    self.description = description
    self.iconName = iconName
    self.weapon = weapon
  }

  var icon: UIImage? {
    return UIImage(named: iconName)
  }
}

這定義了枚舉和類。 枚舉是為了跟蹤不同種類的武器,包括每種武器的圖像。 該類將使用簡單的初始化程序保存怪物信息以創(chuàng)建Monster實(shí)例。

這是用于定義模型的。 接下來,您將它連接到您的主視圖!


Displaying the Monster List

打開MasterViewController.swift并向該類添加一個(gè)新屬性:

let monsters = [
    Monster(name: "Cat-Bot", description: "MEE-OW",
            iconName: "meetcatbot", weapon: .sword),
    Monster(name: "Dog-Bot", description: "BOW-WOW",
            iconName: "meetdogbot", weapon: .blowgun),
    Monster(name: "Explode-Bot", description: "BOOM!",
            iconName: "meetexplodebot", weapon: .smoke),
    Monster(name: "Fire-Bot", description: "Will Make You Steamed",
            iconName: "meetfirebot", weapon: .ninjaStar),
    Monster(name: "Ice-Bot", description: "Has A Chilling Effect",
            iconName: "meeticebot", weapon: .fire),
    Monster(name: "Mini-Tomato-Bot", description: "Extremely Handsome",
            iconName: "meetminitomatobot", weapon: .ninjaStar)
  ]

這可以保存用于填充表視圖的怪物數(shù)組。

找到tableView(_:numberOfRowsInSection :)并將return語句替換為以下內(nèi)容:

return monsters.count

這將根據(jù)數(shù)組的大小返回怪物數(shù)量。

接下來,找到tableView(_:cellForRowAtIndexPath :)并在最終的return語句之前添加以下代碼:

let monster = monsters[indexPath.row]
cell.textLabel?.text = monster.name

這將根據(jù)正確的怪物配置單元格。 這就是table view,它只是顯示每個(gè)怪物的名字。

構(gòu)建并運(yùn)行應(yīng)用程序。

你應(yīng)該在橫屏iPad的左側(cè)看到怪物機(jī)器人列表:

iPhone上:

請(qǐng)記住,在compact-widthiPhone上,您可以在詳細(xì)信息屏幕上的導(dǎo)航堆棧中開始一層深度。 您可以點(diǎn)擊后退按鈕查看table view。


Updating the Master View Controller’s Title

導(dǎo)航欄自動(dòng)設(shè)置初始視圖控制器的標(biāo)題,即RootViewController。

打開Main.storyboard,選擇Root View Controller并雙擊NavigationBar

將其更改為Monster List。 這比Root View Controller好得多。


Displaying Bot Details

現(xiàn)在table view顯示了怪物列表,現(xiàn)在是時(shí)候按順序獲取詳細(xì)視圖了。

打開Main.storyboard,選擇Detail View Controller并刪除之前放下的label。

使用下面的屏幕截圖作為指導(dǎo),將以下控件拖到DetailViewController的視圖中(有關(guān)要添加的內(nèi)容的詳細(xì)列表,請(qǐng)參閱下面的內(nèi)容):

以下是您需要添加的內(nèi)容:

  • 1) 其余視圖將進(jìn)入的容器視圖。這應(yīng)該與屏幕頂部對(duì)齊并在屏幕中水平居中。
  • 2) 一個(gè)95×95的圖像視圖,距離容器視圖頂部8個(gè)像素,距離左側(cè)20個(gè)像素。這是為了顯示怪物的圖像。
  • 3) 與圖像視圖頂部對(duì)齊的label,字體System Bold,大小為30,文本為Monster Name。將其頂部與圖像的頂部對(duì)齊,并將其設(shè)置為圖像右側(cè)的8個(gè)像素。同時(shí)使其尾部邊距容器視圖的右側(cè)8像素。
  • 4) 下面有兩個(gè)帶有System字體的labels,尺寸為24。一個(gè)label應(yīng)與圖像視圖底部對(duì)齊。另一個(gè)label應(yīng)位于第一個(gè)標(biāo)簽下方。它們的左邊緣應(yīng)該對(duì)齊,它們應(yīng)該垂直間隔8個(gè)像素。同時(shí)將這些標(biāo)簽的尾部設(shè)置為距離容器視圖右側(cè)8個(gè)像素。他們應(yīng)該有標(biāo)題DescriptionPreferred way to kill。
  • 5) 一個(gè)70×70的圖像視圖,與Preferred way to kill標(biāo)簽左對(duì)齊,8像素垂直間距。同時(shí)將其底部設(shè)置為距離容器視圖底部8個(gè)像素。

讓自動(dòng)布局使用適當(dāng)?shù)募s束尤其重要,因?yàn)檫@個(gè)應(yīng)用程序是通用的,自動(dòng)布局確保布局適應(yīng)iPad和iPhone。

這就是現(xiàn)在的自動(dòng)布局。 接下來,您需要將這些視圖掛鉤到某些outlets

打開DetailViewController.swift并將以下屬性添加到類的頂部:

@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var descriptionLabel: UILabel!
@IBOutlet weak var iconImageView: UIImageView!
@IBOutlet weak var weaponImageView: UIImageView!

var monster: Monster? {
  didSet {
    refreshUI()
  }
}

在這里,您為剛剛創(chuàng)建的需要?jiǎng)討B(tài)更改的各種UI元素添加了屬性。 您還為此視圖控制器應(yīng)顯示的Monster對(duì)象添加了一個(gè)屬性。

接下來,將以下幫助器方法添加到類中:

private func refreshUI() {
  loadViewIfNeeded()
  nameLabel.text = monster?.name
  descriptionLabel.text = monster?.description
  iconImageView.image = monster?.icon
  weaponImageView.image = monster?.weapon.image
}

無論何時(shí)切換怪物,您都希望UI自行刷新并更新outlets中顯示的詳細(xì)信息。 你甚至可以在視圖加載之前更改monster并觸發(fā)方法。 因此,您調(diào)用loadViewIfNeeded()以保證視圖已加載且其outlets已連接。

現(xiàn)在,打開Main.storyboard。 在Document Outline中右鍵單擊Detail View Controller對(duì)象以顯示插座列表。 從每個(gè)項(xiàng)目右側(cè)的圓圈拖動(dòng)到視圖以連接outlets。

請(qǐng)記住,圖標(biāo)圖像視圖是左上角的大圖像視圖。 武器圖像視圖是Preferred way to kill標(biāo)簽的方式下面較小的一個(gè)。

轉(zhuǎn)到SceneDelegate.swift并使用以下內(nèi)容替換scene(_:willConnectTo:options :)的實(shí)現(xiàn):

guard 
  let splitViewController = window?.rootViewController as? UISplitViewController,
  let leftNavController = splitViewController.viewControllers.first 
    as? UINavigationController,
  let masterViewController = leftNavController.viewControllers.first 
    as? MasterViewController,
  let detailViewController = splitViewController.viewControllers.last 
    as? DetailViewController
  else { fatalError() }

let firstMonster = masterViewController.monsters.first
detailViewController.monster = firstMonster

拆分視圖控制器具有一個(gè)數(shù)組屬性viewControllers,其中包含主控制器和詳細(xì)視圖控制器。 在您的情況下,主視圖控制器實(shí)際上是導(dǎo)航控制器。 因此,要獲取實(shí)際的MasterViewController實(shí)例,請(qǐng)使用導(dǎo)航控制器的第一個(gè)視圖控制器。

要獲取詳細(xì)視圖控制器,請(qǐng)查看拆分視圖控制器的viewControllers數(shù)組中的第二個(gè)視圖控制器。

構(gòu)建并運(yùn)行應(yīng)用程序,您應(yīng)該在右側(cè)看到一些怪物細(xì)節(jié)。

iPad上橫屏:

iPhone

請(qǐng)注意,在MasterViewController上選擇一個(gè)monster什么也沒做,你就永遠(yuǎn)陷入了Cat-Bot。 這就是你接下來要做的事情!


Hooking Up the Master With the Detail

關(guān)于如何在這兩個(gè)視圖控制器之間進(jìn)行最佳通信的策略有很多。 在Master-Detail App模板中,主視圖控制器具有對(duì)詳細(xì)視圖控制器的引用。 這意味著主視圖控制器可以在選擇行時(shí)在詳細(xì)視圖控制器上設(shè)置屬性。

這適用于在詳細(xì)信息窗格中只有一個(gè)視圖控制器的簡單應(yīng)用程序。 但是,您將遵循UISplitViewController類引用中建議的方法來處理更復(fù)雜的應(yīng)用程序并使用委托delegate。

打開MasterViewController.swift并在MasterViewController類定義上面添加以下協(xié)議定義:

protocol MonsterSelectionDelegate: class {
  func monsterSelected(_ newMonster: Monster)
}

這定義了一個(gè)帶有單個(gè)方法的協(xié)議,monsterSelected(_ :)。 詳細(xì)視圖控制器將實(shí)現(xiàn)此方法,并且主視圖控制器將在用戶選擇怪物時(shí)向其發(fā)送消息。

接下來,更新MasterViewController以添加符合委托協(xié)議的對(duì)象的屬性:

weak var delegate: MonsterSelectionDelegate?

基本上,這意味著委托屬性需要是一個(gè)實(shí)現(xiàn)了monsterSelected(_ :)的對(duì)象。 在用戶選擇怪物后,該對(duì)象將負(fù)責(zé)處理其視圖中需要發(fā)生的事情。

由于您希望DetailViewController在用戶選擇怪物時(shí)更新,因此您需要實(shí)現(xiàn)委托。

打開DetailViewController.swift并在文件的最后添加一個(gè)類擴(kuò)展:

extension DetailViewController: MonsterSelectionDelegate {
  func monsterSelected(_ newMonster: Monster) {
    monster = newMonster
  }
}

類擴(kuò)展非常適合分離委托協(xié)議并將方法組合在一起。 在此擴(kuò)展中,您說DetailViewController符合MonsterSelectionDelegate。 然后,您實(shí)現(xiàn)一個(gè)必需的方法。

現(xiàn)在委托方法已準(zhǔn)備就緒,您需要從master方面調(diào)用它。

打開MasterViewController.swift并添加以下方法:

override func tableView(
    _ tableView: UITableView, 
    didSelectRowAt indexPath: IndexPath) {
  let selectedMonster = monsters[indexPath.row]
  delegate?.monsterSelected(selectedMonster)
}

實(shí)現(xiàn)tableView(_:didSelectRowAt :)意味著只要用戶在表視圖中選擇一行,您就會(huì)收到通知。 您需要做的就是通知新怪物的怪物選擇代理。

最后,返回SceneDelegate.swift。 在scene(_:willConnectTo:options:)中,在方法的最后添加以下代碼:

masterViewController.delegate = detailViewController

這是兩個(gè)視圖控制器之間的最終連接。

iPad上構(gòu)建并運(yùn)行應(yīng)用程序。 你現(xiàn)在應(yīng)該可以在monsters之間進(jìn)行選擇,如下所示:

到目前為止,拆分視圖非常好! 但是還有一個(gè)問題:如果你在iPhone上運(yùn)行它,從主表視圖中選擇怪物不會(huì)顯示詳細(xì)視圖控制器。 您現(xiàn)在需要進(jìn)行一些小修改,以確保拆分視圖也適用于iPhone。

打開MasterViewController.swift。 找到tableView(_:didSelectRowAt :)并將以下內(nèi)容添加到方法的末尾:

if let detailViewController = delegate as? DetailViewController {
  splitViewController?.showDetailViewController(detailViewController, sender: nil)
}

首先,您需要確保代理已設(shè)置,并且它是一個(gè)DetailViewController實(shí)例,正如您所期望的那樣。 然后在拆分視圖控制器上調(diào)用showDetailViewController(_:sender :)并傳入詳細(xì)視圖控制器。 UIViewController的每個(gè)子類都有一個(gè)繼承屬性splitViewController,它將引用它容器視圖控制器(如果存在)。

此新代碼僅更改iPhone上應(yīng)用程序的行為,導(dǎo)致導(dǎo)航控制器在您選擇新怪物時(shí)將細(xì)節(jié)控制器推入堆棧。 它不會(huì)改變iPad實(shí)現(xiàn)的行為,因?yàn)樵趇Pad上,細(xì)節(jié)視圖控制器始終可見。

進(jìn)行此更改后,在iPhone上運(yùn)行它現(xiàn)在應(yīng)該正常運(yùn)行。 只需添加幾行代碼,您就可以在iPad和iPhone上使用功能齊全的分割視圖控制器。 不錯(cuò)!


Split View Controller in iPad Portrait

以縱向模式在iPad中運(yùn)行應(yīng)用程序。 起初,似乎沒有辦法進(jìn)入左側(cè)菜單。

但請(qǐng)嘗試從屏幕左側(cè)滑動(dòng)。 很酷吧? 點(diǎn)按菜單外的任意位置即可隱藏它。

內(nèi)置的滑動(dòng)功能非常酷,但是如果你想在導(dǎo)航欄上方放置一個(gè)顯示菜單的按鈕,類似于它在iPhone上的表現(xiàn)怎么辦? 要做到這一點(diǎn),您需要對(duì)應(yīng)用程序進(jìn)行一些小的修改。

首先,打開Main.storyboard并將Detail View Controller嵌入到導(dǎo)航控制器中。 您可以通過選擇詳細(xì)視圖控制器,然后選擇Editor ? Embed In ? Navigation Controller來完成此操作。

您的故事板現(xiàn)在看起來像這樣:

現(xiàn)在打開MasterViewController.swift并找到tableView(_:didSelectRowAt :)。 通過調(diào)用showDetailViewController(_:sender :)if塊更改為以下內(nèi)容:

if 
  let detailViewController = delegate as? DetailViewController,
  let detailNavigationController = detailViewController.navigationController {
    splitViewController?
      .showDetailViewController(detailNavigationController, sender: nil)
}

現(xiàn)在,您將顯示詳細(xì)視圖控制器的導(dǎo)航控制器,而不是顯示詳細(xì)視圖控制器。 無論如何,導(dǎo)航控制器的根目錄是詳細(xì)視圖控制器,因此您仍然可以看到與之前相同的內(nèi)容,只需將其包含在導(dǎo)航控制器中。

在運(yùn)行應(yīng)用程序之前,最后要進(jìn)行兩項(xiàng)更改。

首先,在SceneDelegate.swift更新scene(_willConnectTo:options:)中,通過替換初始化detailViewController的行來解釋DetailViewController現(xiàn)在包含在導(dǎo)航控制器中的事實(shí):

let detailViewController = 
  (splitViewController.viewControllers.last as? UINavigationController)?
    .topViewController as? DetailViewController

由于詳細(xì)視圖控制器包含在導(dǎo)航控制器中,因此現(xiàn)在有兩個(gè)步驟來訪問它。

最后,在方法結(jié)束之前添加以下行。

detailViewController.navigationItem.leftItemsSupplementBackButton = true
detailViewController.navigationItem.leftBarButtonItem = 
  splitViewController.displayModeButtonItem

這告訴詳細(xì)視圖控制器用一個(gè)按鈕替換其左側(cè)導(dǎo)航項(xiàng),該按鈕將切換拆分視圖控制器的顯示模式。 在iPhone上運(yùn)行時(shí)不會(huì)改變?nèi)魏螙|西,但在iPad上,你會(huì)在左上角看到一個(gè)按鈕來切換table view顯示。

iPad豎屏上運(yùn)行應(yīng)用程序并檢查:

現(xiàn)在,您可以在縱向和橫向上在iPadiPhone上運(yùn)行良好的效果!

后記

本篇主要講述了一個(gè)UISplitViewController的簡單實(shí)用示例,感興趣的給個(gè)贊或者關(guān)注~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容