版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2019.01.19 星期六 |
前言
IGListKit
這個框架可能很多人沒有聽過,它其實就是一個數據驅動的UICollectionView
框架,用于構建快速靈活的列表。它由
1. IGListKit框架詳細解析(一) —— 基本概覽(一)
2. IGListKit框架詳細解析(二) —— 基于IGListKit框架的更好的UICollectionViews簡單示例(一)
Adding Messages
JPL
工程師非常高興您能夠快速完成重構,但他們確實需要與被困的宇航員建立聯系。 他們已經要求您盡快集成消息模塊ASAP
。
在添加任何視圖之前,首先需要數據。
打開FeedViewController.swift
并在FeedViewController
的頂部添加一個新屬性:
let pathfinder = Pathfinder()
PathFinder()
充當消息系統,代表宇航員在火星上挖出的物理Pathfinder漫游者。
在ListAdapterDataSource
擴展中找到objects(for:)
并修改內容以匹配以下內容:
var items: [ListDiffable] = pathfinder.messages
items += loader.entries as [ListDiffable]
return items
您可能還記得,此方法為ListAdapter
提供了數據源對象。 此處的修改將pathfinder.messages
添加到items
以為新的控制器提供消息。
注意:您必須強制轉換
entries
數組以使Swift編譯器可以使用。 對象已經遵循IGListDiffable
。
右鍵單擊SectionControllers
組以創建名為MessageSectionController
的新ListSectionController
子類。 將IGListKit
的import
添加到頂部:
import IGListKit
編譯器可以使用,你現在可以保持其余的不變。
返回FeedViewController.swift
并更新ListAdapterDataSource
擴展中的listAdapter(_:sectionControllerFor :)
,使其顯示如下:
if object is Message {
return MessageSectionController()
} else {
return JournalSectionController()
}
如果數據對象的類型為Message
,則現在返回新的message section controller
。
JPL
團隊希望您設置具有以下要求的MessageSectionController
:
- 收到消息
Message
。 - 有一個15點的
bottom inset
。 - 返回使用
MessageCell.cellSize(width:text :)
方法調整大小的單個單元格。 - 使用
Message
對象的text
和user.name
值對MessageCell
進行出隊和配置以填充標簽。 - 在所有大寫中顯示
Message
對象的user.name
值。
試一試! 如果您需要幫助,該團隊會在下面起草一個解決方案。
import IGListKit
class MessageSectionController: ListSectionController {
var message: Message!
override init() {
super.init()
inset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0)
}
}
// MARK: - Data Provider
extension MessageSectionController {
override func numberOfItems() -> Int {
return 1
}
override func sizeForItem(at index: Int) -> CGSize {
guard let context = collectionContext else {
return .zero
}
return MessageCell
.cellSize(width: context.containerSize.width, text: message.text)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell = collectionContext?
.dequeueReusableCell(of: MessageCell.self, for: self, at: index)
as! MessageCell
cell.messageLabel.text = message.text
cell.titleLabel.text = message.user.name.uppercased()
return cell
}
override func didUpdate(to object: Any) {
message = object as? Message
}
}
準備好后,構建并運行以查看集成到Feed中的消息!
Weather on Mars
你的宇航員需要能夠獲得當前的天氣,以便在沙塵暴等障礙物周圍航行。 JPL構建了另一個顯示當前天氣的模塊。 那里有很多信息,所以他們要求天氣只在點擊時顯示。
創建一個名為WeatherSectionController
的最后一個section controller
。 使用初始化程序和一些變量啟動class:
import IGListKit
class WeatherSectionController: ListSectionController {
// 1
var weather: Weather!
// 2
var expanded = false
override init() {
super.init()
// 3
inset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0)
}
}
這段代碼的作用:
- 1) 此
section controller
將在didUpdate(to :)
中接收Weather
對象。 - 2)
expanded
是一個Bool
,用于跟蹤宇航員是否擴大了天氣section
。 您將其初始化為false
,以便最初折疊詳細信息單元格。 - 3) 與其他section一樣,使用15點的
bottom inset
。
現在為WeatherSectionController
添加一個擴展并重寫三個方法:
// MARK: - Data Provider
extension WeatherSectionController {
// 1
override func didUpdate(to object: Any) {
weather = object as? Weather
}
// 2
override func numberOfItems() -> Int {
return expanded ? 5 : 1
}
// 3
override func sizeForItem(at index: Int) -> CGSize {
guard let context = collectionContext else {
return .zero
}
let width = context.containerSize.width
if index == 0 {
return CGSize(width: width, height: 70)
} else {
return CGSize(width: width, height: 40)
}
}
}
下面就是工作原理:
- 1) 在
didUpdate(to :)
中,保存傳遞的Weather
對象。 - 2) 如果您正在顯示擴展天氣,則
numberOfItems()
將返回包含不同天氣數據的五個單元格。如果未展開,則只需要一個單元格即可顯示占位符。 - 3) 第一個單元格應該比其他單元格大一些,因為它顯示標題。您不必檢查展開
expanded
狀態,因為該header
單元格是兩種情況下的第一個單元格。
接下來,您需要實現cellForItem(at :)
來配置天氣單元格。以下是一些詳細要求:
- 第一個單元格應為
WeatherSummaryCell
類型,其他單元格應為WeatherDetailCell
。 - 使用
cell.setExpanded(_ :)
配置天氣摘要單元格。 - 使用以下標題和詳細信息標簽配置四個不同的天氣細節單元格:
“Sunrise” with weather.sunrise
“Sunset” with weather.sunset
“High” with "\(weather.high) C"
“Low” with "\(weather.low) C"
給這個cell一個截圖,解決方案就在下面。
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cellClass: AnyClass =
index == 0 ? WeatherSummaryCell.self : WeatherDetailCell.self
let cell = collectionContext!
.dequeueReusableCell(of: cellClass, for: self, at: index)
if let cell = cell as? WeatherSummaryCell {
cell.setExpanded(expanded)
} else if let cell = cell as? WeatherDetailCell {
let title: String, detail: String
switch index {
case 1:
title = "SUNRISE"
detail = weather.sunrise
case 2:
title = "SUNSET"
detail = weather.sunset
case 3:
title = "HIGH"
detail = "\(weather.high) C"
case 4:
title = "LOW"
detail = "\(weather.low) C"
default:
title = "n/a"
detail = "n/a"
}
cell.titleLabel.text = title
cell.detailLabel.text = detail
}
return cell
}
您需要做的最后一件事是切換展開的部分并在點擊時更新單元格。 重寫ListSectionController
另一個方法:
override func didSelectItem(at index: Int) {
collectionContext?.performBatch(animated: true, updates: { batchContext in
self.expanded.toggle()
batchContext.reload(self)
}, completion: nil)
}
performBatch(animated:updates:completion :)
批量處理并在單個事務中執行更新。 只要控制器中的內容或單元數發生變化,就可以使用它。 由于您使用numberOfItems()
切換擴展,因此將根據expanded
標志添加或刪除單元格。
返回FeedViewController.swift
并在FeedViewController
頂部附近添加以下內容:
let wxScanner = WxScanner()
WxScanner
是天氣條件的模型對象。
接下來,更新ListAdapter DataSource
擴展中的objects(for:)
,使其如下所示:
// 1
var items: [ListDiffable] = [wxScanner.currentWeather]
items += loader.entries as [ListDiffable]
items += pathfinder.messages as [ListDiffable]
// 2
return items.sorted { (left: Any, right: Any) -> Bool in
guard let
left = left as? DateSortable,
let right = right as? DateSortable
else {
return false
}
return left.date > right.date
}
您已更新數據源方法以包含currentWeather
。 以下是有關此功能的詳細信息:
- 1) 將
currentWeather
添加到items
數組中。 - 2) 所有數據都符合
DataSortable
協議,因此使用該協議對數據進行排序。 這可確保數據按時間順序顯示。
最后,更新listAdapter(_:sectionControllerFor :)
以顯示如下:
if object is Message {
return MessageSectionController()
} else if object is Weather {
return WeatherSectionController()
} else {
return JournalSectionController()
}
當Weather
對象出現時,返回WeatherSectionController
。
建立并再次運行。 您應該在頂部看到新的天氣對象。 嘗試點擊該部分以展開和收縮它。
Performing Updates
JPL
對你的進步感到欣喜若狂!
在你工作的時候,美國宇航局局長協調了宇航員的救援行動,要求他發射并攔截另一艘船! 這將是一個復雜的發射,所以他將不得不在恰當的時間升空。
JPL工程部門通過實時聊天擴展了消息傳遞模塊,他們要求您對其進行集成。
打開FeedViewController.swift
并將以下行添加到viewDidLoad()
的末尾:
pathfinder.delegate = self
pathfinder.connect()
Pathfinder
模塊都經過實時支持修補。 您需要做的就是連接到設備并響應委托事件。
將以下擴展添加到文件的底部:
// MARK: - PathfinderDelegate
extension FeedViewController: PathfinderDelegate {
func pathfinderDidUpdateMessages(pathfinder: Pathfinder) {
adapter.performUpdates(animated: true)
}
}
FeedViewController
現在符合PathfinderDelegate
。 單個方法performUpdates(animated :)
告訴ListAdapter
向其數據源詢問新對象,然后更新UI。 它處理被刪除,更新,移動或插入的對象。
構建并運行以查看隊長的消息更新! 您所要做的就是為IGListKit添加一個方法,以確定數據源中的更改內容,并在新數據到達時為更改設置動畫:
您現在需要做的就是將最新版本傳輸給宇航員,他將回家!
后記
本篇主要簡單介紹了基于IGListKit框架的更好的UICollectionViews簡單示例,感興趣的給個贊或者關注~~~