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

版本記錄

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

前言

iOS中有關(guān)視圖控件用戶(hù)能看到的都在UIKit框架里面,用戶(hù)交互也是通過(guò)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布局的簡(jiǎn)單示例(一)
16. UIKit框架(十六) —— 基于自定義UICollectionViewLayout布局的簡(jiǎn)單示例(二)
17. UIKit框架(十七) —— 基于自定義UICollectionViewLayout布局的簡(jiǎn)單示例(三)
18. UIKit框架(十八) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫(huà)的實(shí)現(xiàn)(一)
19. UIKit框架(十九) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫(huà)的實(shí)現(xiàn)(二)
20. UIKit框架(二十) —— 基于UILabel跑馬燈類(lèi)似效果的實(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的自定義布局 (二)

開(kāi)始

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

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

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

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

Swift 5, iOS 13, Xcode 11

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

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

您將使用拆分視圖控制器來(lái)處理導(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)乡摹,但您將從頭開(kāi)始使用Single View App模板。 這將使您更好地了解UISplitViewController的工作原理采转。 在將來(lái)的項(xiàng)目中使用UISplitViewController時(shí)聪廉,這些知識(shí)將非常有用。

是時(shí)候創(chuàng)建UI了故慈,所以打開(kāi)Main.storyboard板熊。

刪除故事板中的默認(rèn)初始View Controller Scene。 同時(shí)從項(xiàng)目導(dǎo)航器中刪除ViewController.swift察绷,確保在詢(xún)問(wèn)時(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)航控制器具有稱(chēng)為master view controller的關(guān)系segue蚜印。 這允許您在主視圖控制器中創(chuàng)建整個(gè)導(dǎo)航層次結(jié)構(gòu),而無(wú)需影響詳細(xì)視圖控制器娶视。
  • View Controller - 視圖控制器:這將最終顯示所有怪物的詳細(xì)信息晒哄。 如果查看拆分視圖控制器,您將看到視圖控制器具有稱(chēng)為詳細(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伐债,然后打開(kāi)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ì)看到它開(kāi)始全屏顯示細(xì)節(jié)視圖塘辅。 它還允許您點(diǎn)擊導(dǎo)航欄上的后退按鈕以彈回主視圖控制器:

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

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


Creating Custom View Controllers

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

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

打開(kāi)MasterViewController.swift蓖议。

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

接下來(lái),找到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è)空行质况。

打開(kāi)Main.storyboard愕宋。 選擇Root View Controller并切換Identity檢查器。 將類(lèi)更改為MasterViewController结榄。

此外中贝,您需要確保在表視圖中為原型單元格提供重用標(biāo)識(shí)符。 如果沒(méi)有臼朗,它會(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模板缭乘。 將類(lèi)命名為DetailViewController,并使其成為UIViewController的子類(lèi)琉用。 確保未選中Also create XIB file復(fù)選框堕绩,并將Language設(shè)置為Swift策幼。

單擊Next,然后單擊Create奴紧。

打開(kāi)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è)位都有自定義視圖控制器。 接下來(lái)你需要添加那些討厭的怪物痊末。


Making Your Model

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

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

您將創(chuàng)建一個(gè)簡(jiǎn)單的類(lèi)罗心,其中包含有關(guān)要顯示的每個(gè)怪物的屬性屬性。 您還將實(shí)現(xiàn)一些方法來(lái)創(chuàng)建新的怪物并訪問(wèn)每個(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)
  }
}

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

這是用于定義模型的。 接下來(lái),您將它連接到您的主視圖补憾!


Displaying the Monster List

打開(kāi)MasterViewController.swift并向該類(lèi)添加一個(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語(yǔ)句替換為以下內(nèi)容:

return monsters.count

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

接下來(lái)盈匾,找到tableView(_:cellForRowAtIndexPath :)并在最終的return語(yǔ)句之前添加以下代碼:

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)航堆棧中開(kāi)始一層深度启昧。 您可以點(diǎn)擊后退按鈕查看table view


Updating the Master View Controller’s Title

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

打開(kāi)Main.storyboard,選擇Root View Controller并雙擊NavigationBar跛璧。

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


Displaying Bot Details

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

打開(kāi)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)布局敬辣。 接下來(lái),您需要將這些視圖掛鉤到某些outlets零院。

打開(kāi)DetailViewController.swift并將以下屬性添加到類(lèi)的頂部:

@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è)屬性门粪。

接下來(lái)喊积,將以下幫助器方法添加到類(lèi)中:

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

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

現(xiàn)在绎签,打開(kāi)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什么也沒(méi)做赂毯,你就永遠(yuǎn)陷入了Cat-Bot。 這就是你接下來(lái)要做的事情拣宰!


Hooking Up the Master With the Detail

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

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

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

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

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

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

weak var delegate: MonsterSelectionDelegate?

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

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

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

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

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

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

打開(kāi)MasterViewController.swift并添加以下方法:

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

實(shí)現(xiàn)tableView(_:didSelectRowAt :)意味著只要用戶(hù)在表視圖中選擇一行,您就會(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è)問(wèn)題:如果你在iPhone上運(yùn)行它酪术,從主表視圖中選擇怪物不會(huì)顯示詳細(xì)視圖控制器。 您現(xiàn)在需要進(jìn)行一些小修改翠储,以確保拆分視圖也適用于iPhone绘雁。

打開(kāi)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è)子類(lèi)都有一個(gè)繼承屬性splitViewController,它將引用它容器視圖控制器(如果存在)滔岳。

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

進(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)用程序。 起初疲憋,似乎沒(méi)有辦法進(jìn)入左側(cè)菜單凿渊。

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

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

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

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

現(xiàn)在打開(kāi)MasterViewController.swift并找到tableView(_:didSelectRowAt :)。 通過(guò)調(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ì)視圖控制器。 無(wú)論如何团滥,導(dǎo)航控制器的根目錄是詳細(xì)視圖控制器竿屹,因此您仍然可以看到與之前相同的內(nèi)容,只需將其包含在導(dǎo)航控制器中灸姊。

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

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

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

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

最后诗充,在方法結(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è)按鈕來(lái)切換table view顯示茎匠。

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

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

后記

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谊惭,隨后出現(xiàn)的幾起案子汽馋,更是在濱河造成了極大的恐慌,老刑警劉巖圈盔,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豹芯,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡驱敲,警方通過(guò)查閱死者的電腦和手機(jī)铁蹈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)众眨,“玉大人握牧,你說(shuō)我怎么就攤上這事容诬。” “怎么了沿腰?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵览徒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我矫俺,道長(zhǎng),這世上最難降的妖魔是什么掸冤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任厘托,我火速辦了婚禮,結(jié)果婚禮上稿湿,老公的妹妹穿的比我還像新娘铅匹。我一直安慰自己,他們只是感情好饺藤,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布包斑。 她就那樣靜靜地躺著,像睡著了一般涕俗。 火紅的嫁衣襯著肌膚如雪罗丰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天再姑,我揣著相機(jī)與錄音萌抵,去河邊找鬼。 笑死元镀,一個(gè)胖子當(dāng)著我的面吹牛绍填,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播栖疑,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼讨永,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了遇革?” 一聲冷哼從身側(cè)響起卿闹,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萝快,沒(méi)想到半個(gè)月后比原,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杠巡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年量窘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氢拥。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚌铜,死狀恐怖锨侯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冬殃,我是刑警寧澤囚痴,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站审葬,受9級(jí)特大地震影響深滚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜涣觉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一痴荐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧官册,春花似錦生兆、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至员淫,卻和暖如春合蔽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背介返。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工辈末, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人映皆。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓挤聘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親捅彻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子组去,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容