版本记录
版本号 | 时间 |
---|---|
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简单示例,感兴趣的给个赞或者关注~~~