第十二章——子類化UITableViewCell【譯】

UITableView 顯示一個 UITableViewCell 對象的列表。 對于許多應用程序,具有 textLabeldetailTextLabelimageView 的基本 cell 就足夠了。 但是,當您需要具有更多細節(jié)或不同布局的單元格時,可以將 UITableViewCell 子類化。

在本章中,您將創(chuàng)建一個名為 ItemCellUITableViewCell 子類,將更有效地顯示 Item 實例。 每個 cell 都將顯示 Item 的名稱,美元值 和 序列號(圖12.1)。

圖12.1 具有子類化的表視圖 cell 的 Homepwner

您可以通過將子視圖添加到其 contentView 來自定義 UITableViewCell 子類的外觀。 將子視圖添加到 contentView 而不是直接到 cell 本身很重要,因為 cell 會在某些時候調(diào)整其 contentView 的大小。 例如,當表視圖進入編輯模式時,contentView 將自己調(diào)整大小,為編輯控件騰出空間(圖12.2)。 如果您將子視圖直接添加到 UITableViewCell,則編輯控件會掩蓋子視圖。 進入編輯模式時,cell 不能調(diào)整其大?。ㄋ仨毐3直硪晥D的寬度),但是 contentView 可以。

圖12.2 標準和編輯模式下的表視圖 cell 布局

創(chuàng)建 ItemCell

創(chuàng)建一個名為 ItemCell 的新 Swift 文件。 在 ItemCell.swift 中,將 ItemCell 定義為 UITableViewCell 子類。

import Foundation
import UIKit

class ItemCell: UITableViewCell {

}

最簡單的配置 UITableViewCell 子類的方法是通過故事板。 在第10章中,您看到表視圖控制器的故事板具有 Prototype Cells 部分。 這是您將為 ItemCell 制作內(nèi)容的地方。

打開 Main.storyboard 并在文檔大綱中選擇 UITableViewCell。 打開屬性檢查器,將 Style 更改為 Custom,并將 Identifier 更改為 ItemCell。

現(xiàn)在打開它的身份檢查器,圖標


。 在 Class 字段中,輸入 ItemCell(圖12.3)。

圖12.3更改 cell 的類

將 prototype cell 的高度更改為約 65 點。 您可以在畫布上或通過選擇表視圖 cell 并從其大小檢查器更改 Row Height 來進行更改。

ItemCell 將顯示三個文本元素,因此將三個 UILabel 對象拖動到單元格上。 配置如圖12.4所示。 將底部標簽的文字設為稍微較小的灰色字體。 確保標簽一點也不重疊。

圖12.4 ItemCell 的布局

對這三個標簽添加約束如下。

  1. 選擇左上角的標簽并打開 Add New Constraints 菜單。 選擇頂部和左側(cè)支柱,然后單擊 Add 2 Constraints
  2. 您希望左下角的標簽始終與左上角的標簽對齊。 右鍵從左下角的標簽拖動到左上角的標簽,然后選擇 Leading。
  3. 選中左下方的標簽,打開 Add New Constraints 菜單,選擇底部的支柱,然后單擊 Add 1 Constraint
  4. 選擇正確的標簽,然后右擊從右側(cè)的控件拖動到其父視圖。 選擇 Trailing Space to Container MarginCenter Vertically in Container
  5. 選擇左下角的標簽并打開其尺寸檢查器。 查找 Vertical Content Hugging Priority 并將其降低到 250.將 Vertical Content Compression Resistance Priority 降低到749.您將在第13章中了解這些自動布局屬性的功能。
  6. 您的邊框可能顯示在錯誤的位置,因此請選中三個標簽,然后單擊 Update Frames 按鈕。

暴露 ItemCell的屬性

要通過 ItemsViewController 來配置 TableView(_:cellForRowAt :) 中的 ItemCell 的內(nèi)容,cell 必須有暴露這三個標簽的屬性。 這些屬性將通過 Main.storyboard 中的 outlet 連接來設置。

那么下一步就是在 ItemCell 上為每個子視圖創(chuàng)建和連接 outlet。

打開 ItemCell.swift 并為 outlet 添加三個屬性。

import UIKit

class ItemCell: UITableViewCell {

??@IBOutlet var nameLabel: UILabel!
??@IBOutlet var serialNumberLabel: UILabel!
??@IBOutlet var valueLabel: UILabel!

}

你將連接三個視圖的 outlet 到 ItemCell。 當在書中較早連接 outlet 時,您可以從故事板中的視圖控制器拖動到相應的視圖。 但連接 ItemCell 的 outlet 不是控制器上的 outlet。 它們是另一個視圖中的 outlet:自定義的 UITableViewCell 子類。

因此,要連接 ItemCell 的 outlet,您將要連接到 ItemCell。

打開 Main.storyboard。 右擊文檔輪廓中的 ItemCell,并使三個 outlet 連接如圖12.5所示。

圖12.5連接 outlet

使用 ItemCell

讓我們在屏幕上看到你的自定義單元格。 在 ItemViewControllertableView(_:cellForRowAt :) 方法中,您將在表中的每一行顯示一個 ItemCell 的實例。

現(xiàn)在您正在使用自定義 UITableViewCell 子類,表視圖需要知道每行的高度。 有幾種方法可以實現(xiàn)此目的,但最簡單的方法是將表視圖的 rowHeight 屬性設置為常量值。 本章稍后將會看到另一種方式。

打開 ItemsViewController.swift 并更新 viewDidLoad() 來設置表視圖 cell 的高度。

override func viewDidLoad() {
??super.viewDidLoad()

??// Get the height of the status bar
??let statusBarHeight = UIApplication.shared.statusBarFrame.height

??let insets = UIEdgeInsets(top: statusBarHeight, left: 0, bottom: 0, right: 0)
??tableView.contentInset = insets
??tableView.scrollIndicatorInsets = insets

??tableView.rowHeight = 65
}

請注意,您已經(jīng)使用表格視圖(使用故事板中的 prototype cell)注冊了 ItemCell,您可以要求表格視圖將具有標識符 “ItemCell” 的 cell 列出。

在 ItemsViewController.swift 中,修改 tableView(_:cellForRowAt :)。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
??// Get a new or recycled cell

??let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell",for: indexPath)

??let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell

??// Set the text on the cell with the description of the item
??// that is at the nth index of items, where n = row this cell
??// will appear in on the tableview
??let item = itemStore.allItems[indexPath.row]

??//cell.textLabel?.text = item.name
??//cell.detailTextLabel?.text = "$\(item.valueInDollars)"

??// Configure the cell with the Item
??cell.nameLabel.text = item.name
??cell.serialNumberLabel.text = item.serialNumber
??cell.valueLabel.text = "$\(item.valueInDollars)"

??return cell
}

首先,更新重用標識符以反映您的新子類。 該方法結(jié)束時的代碼是相當明顯的——對于單元格上的每個標簽,將其 text 設置為相應的 Item 的某些屬性。

構(gòu)建并運行應用程序。 現(xiàn)在,新的 cell 加載了它們的標簽,并填充了每個 Item 的值。

動態(tài)單元格高度

目前,cell 的固定高度為 65 點。 更好的是根據(jù) cell 的內(nèi)容來修改它的高度。 這樣,如果內(nèi)容更改,表視圖 cell 的高度可以自動更改。

您可以通過自動布局實現(xiàn)這一目標,就像您已經(jīng)猜到的那樣。 UITableViewCell 需要具有垂直約束,以確定 cell 的高度。 目前,ItemCell 沒有足夠的限制。 您需要在兩個左側(cè)標簽之間添加一個約束,這些約束修正了它們之間的垂直間距。

打開 Main.storyboard。 右擊從 nameLabel 拖動到 serialNumberLabel 并選擇 Vertical Spacing。

現(xiàn)在打開 ItemsViewController.swift 并更新 viewDidLoad() 來告訴表視圖它應該基于約束來計算 cell 高度。

override func viewDidLoad() {
??super.viewDidLoad()

??// Get the height of the status bar
??let statusBarHeight = UIApplication.shared.statusBarFrame.height

??let insets = UIEdgeInsets(top: statusBarHeight, left: 0, bottom: 0, right: 0)
??tableView.contentInset = insets
??tableView.scrollIndicatorInsets = insets

??//tableView.rowHeight = 65
??tableView.rowHeight = UITableViewAutomaticDimension
??tableView.estimatedRowHeight = 65
}

UITableViewAutomaticDimensionrowHeight 的默認值,所以這其實沒有必要添加,這里是為了讓你理解。 在表視圖中設置 estimateRowHeight 屬性可以提高性能。設置此屬性可以節(jié)省某些性能成本,直到用戶開始滾動而不是表視圖加載時才請求每個 cell 的高度。

構(gòu)建并運行應用程序。 該應用程序?qū)⒖雌饋硐褚郧耙粯印?在下一節(jié)中,您將了解一種稱為 動態(tài)類型(Dynamic Type) 的技術(shù),該技術(shù)適用于自動調(diào)整大小的表視圖單元格。

動態(tài)類型

創(chuàng)建一個能吸引每一個人的界面可能是很難的。 有些人喜歡更緊湊的界面,因此他們可以一次看到更多的信息。 其他人可能希望能夠一目了然地輕松查看信息,也許他們的視力較差。 總之:人們有不同的需求。 良好的開發(fā)人員力求使應用程序能夠滿足這些需求。

動態(tài)類型(Dynamic Type) 是一種通過提供專門設計的文本樣式來幫助實現(xiàn)這一目標的技術(shù),這些文本樣式被優(yōu)化為可讀性。 用戶可以從 Apple 的 設置(Settings) 應用程序中選擇七種首選文本大小之一(另外還有一些可擴展性部分中的其他更大的尺寸),支持動態(tài)類型的應用程序的字體可以適當?shù)乜s放。 在本節(jié)中,您將更新 ItemCell 以支持動態(tài)類型。 圖12.6 顯示了以最小和最大用戶可選動態(tài)類型大小呈現(xiàn)的應用程序。

圖12.6支持動態(tài)類型的ItemCell

動態(tài)類型系統(tǒng)以文本樣式為中心。 當為給定的文本樣式請求字體時,系統(tǒng)將考慮與文本樣式相關(guān)聯(lián)的用戶首選文本大小以返回適當配置的字體。 圖12.7顯示了不同的文字樣式。

圖12.7 文字樣式

打開 Main.storyboard。 讓我們更新標簽以使用文本樣式,而不是固定的字體。 選擇 nameLabelvalueLabel 并打開屬性檢查器。 點擊 Font 右邊的文本圖標。 對于 Font,選擇 Text Styles - Body (圖12.8)。 對 serialNumberLabel 重復相同的步驟,選擇 Caption 1 文本樣式。

圖12.8 更改文本樣式

現(xiàn)在我們來更改首選的字體大小。 您可以通過 設置(Settings) 應用程序來執(zhí)行

構(gòu)建并運行應用程序。 從模擬器的 Hardware 菜單中,選擇 Home。 接下來,在模擬器的主屏幕上,打開 Settings 應用程序。 選擇 General,然后選擇 Accessibility,然后選擇 Larger Text。 (在實際的設備上,也可以通過 Display & BrightnessText SizeSettings 中訪問此菜單。)將滑塊一直向左拖動以將字體大小設置為最小值(圖12.9)。

圖12.9 文字大小設置

構(gòu)建并運行應用程序。 (如果您切換回應用程序,使用任務切換器或通過主屏幕,將不會看到更改,您將在下一節(jié)中進行修復。)將一些 item 添加到表視圖中,您將看到新的較小的字體尺寸。

響應用戶更改

當用戶更改首選文本大小并返回到應用程序時,表視圖將被重新加載。 不幸的是,標簽不會知道新的首選文本大小。 要解決這個問題,您需要將標簽根據(jù)內(nèi)容大小的更改而自動調(diào)整。

打開 ItemCell.swift 并覆蓋 awakeFromNib() 使標簽自動調(diào)整。

override func awakeFromNib() {
??super.awakeFromNib()

??nameLabel.adjustsFontForContentSizeCategory = true
??serialNumberLabel.adjustsFontForContentSizeCategory = true
??valueLabel.adjustsFontForContentSizeCategory = true
}

從一個歸檔文件中加載之后,方法 awakeFromNib() 會被一個對象所調(diào)用,在這種情況下,它就是故事板文件。 到這個方法被調(diào)用的時候,所有的 outlet 都有值,可以被使用。

構(gòu)建并運行應用程序并添加幾行。 進入 Settings,將首選閱讀尺寸更改為最大尺寸。 與以前不同,現(xiàn)在可以通過打開任務切換器或通過主屏幕切換回 Homepwner,并且表視圖將更新以反映新的首選文本大小。

青銅挑戰(zhàn):cell 顏色

如果值小于50,則更新 ItemCell 以將 valueInDollars 顯示為綠色,如果值大于或等于 50,則顯示為紅色。

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

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

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