CollectionKit
重新构想UICollectionView
一个用于构建可组合数据驱动的集合视图的现代Swift框架。
迁移指南
功能
- 在
UIScrollView
之上重写UICollectionView
。 - 自动区别数据变化并更新UI。
- 通过cell重用、批量重载、仅视口diff以及 Swift值类型的使用,实现超凡性能。
- 专为集合构建的内置布局和动画系统。
- 具有独立布局的可组合部分。
- 由Swift泛型驱动的严格类型检查。
安装
# CocoaPods
pod "CollectionKit"
# Carthage
github "SoySauceLab/CollectionKit"
入门指南
要开始使用CollectionKit,请用CollectionView
替换UICollectionView
。CollectionView
是CollectionKit对UICollectionView
的替代。你给它一个Provider
对象,这个对象告诉CollectionView
如何显示集合。
构建Provider最简单的方法是使用BasicProvider
类。
BasicProvider
要构建一个BasicProvider
,你需要以下内容
- 数据源
- 一个为BasicProvider提供数据的对象。
- 视图源
- 一个对象,将每个数据映射到视图,并根据需要进行视图更新。
- 尺寸源
- 一个函数,为每个单元格提供大小。
听起来很复杂,但事实上并不复杂。以下是一个简短的示例,演示了它是如何工作的。
let dataSource = ArrayDataSource(data: [1, 2, 3, 4])
let viewSource = ClosureViewSource(viewUpdater: { (view: UILabel, data: Int, index: Int) in
view.backgroundColor = .red
view.text = "\(data)"
})
let sizeSource = { (index: Int, data: Int, collectionSize: CGSize) -> CGSize in
return CGSize(width: 50, height: 50)
}
let provider = BasicProvider(
dataSource: dataSource,
viewSource: viewSource,
sizeSource: sizeSource
)
//lastly assign this provider to the collectionView to display the content
collectionView.provider = provider
请注意,我们在这里使用了ArrayDataSource
和ClosureViewSource
。这两个类是CollectionKit内建的,应该能够满足大多数任务。你也可以实现自己的dataSource
和viewSource
。想象一下在你的项目中实现一个NetworkDataSource
,它可以从json数据中检索并解析swift对象。
刷新
使用新数据更新CollectionView很容易。
dataSource.data = [7, 8, 9]
这将触发由此dataSource所服务的CollectionView进行更新。
请注意,append
和其他数组的mutating方法也可用。
dataSource.data.append(10)
dataSource.data.append(11)
dataSource.data.append(12)
在这个例子中,我们更新了数组三次。每次更新都会触发一个刷新。你可能认为这非常计算密集,但事实并非如此。CollectionKit足够智能,只会在每个布局周期更新一次。它将等到下一次布局周期才真正刷新。
执行了上述3行代码后,CollectionView仍会显示[7, 8, 9]
。但一旦完成当前运行循环周期,CollectionView会立即更新。你的用户不会注意到这个过程有任何滞后。
要立即触发更新,你可以调用collectionView.reloadData
或provider.reloadData
或dataSource reloadData
。
要使CollectionView在下一个布局周期刷新,你可以调用collectionView.setNeedsReload
或provider.setNeedsReload
或dataSource.setNeedsReload
。你可能已经注意到,一旦你更新了ArrayDataSource
内部的数组,基本上就是在为你调用setNeedsReload
。
请注意,如果你将数组分配给dataSource,然后更新这个数组,实际上并不会更新CollectionView。
var a = [1, 2 ,3]
dataSource.data = a
a.append(5) // won't trigger an update be cause dataSource.data & a is now two different array.
a = [4 ,5 ,6] // also won't trigger an update
布局
到如今,这个列表看起来仍然有些丑陋。每个单元格都靠左对齐,且之间没有任何间距。你可能会想要视图均匀分布,或者你可能会想要在项目或行之间添加一些间距。
这些都可以通过布局对象来实现。这里有一个例子。
provider.layout = FlowLayout(spacing: 10, justifyContent: .center)
FlowLayout
是 CollectionKit 内置的一个 Layout
类。还有许多其他内置布局,包括 WaterfallLayout
和 RowLayout
。你也可以轻松地创建自己的布局。
FlowLayout
实际上是一个更高级的 UICollectionViewFlowLayout
,它以行行的形式排列项目。它支持 lineSpacing
、interitemSpacing
、alignContent
、alignItems
和 justifyContent
。
每个布局也支持 inset(by:)
和 transposed()
方法。
inset(by:)
为布局添加外部填充,并将结果布局作为 InsetLayout
返回。
let inset = UIEdgeInset(top: 10, left: 10, bottom: 10, right: 10)
provider.layout = FlowLayout(spacing: 10).inset(by: inset)
transposed()
将垂直布局转换为水平布局,或反之亦然。它返回原始布局被包装在 TransposedLayout
中。
provider.layout = FlowLayout(spacing: 10).transposed()
你还可以同时使用它们,如下所示
let inset = UIEdgeInset(top: 10, left: 10, bottom: 10, right: 10)
provider.layout = FlowLayout(spacing: 10).transposed().inset(by: inset)
关于布局有很多可以说的。我们将来会创建更多教程,教你如何创建自己的布局,并展示一些高级用法。与此同时,欢迎深入了解源代码。我向你保证它一点也不复杂。
组合(ComposedProvider)
CollectionKit 最好的特性之一,就是你可以将提供者自由组合在一起,在一个 CollectionView 中创建多个部分,而且这样做 确实非常简单。
let finalProvider = ComposedProvider(sections: [provider1, provider2, provider3])
collectionView.provider = finalProvider
要更新单独的部分,只需更新其自己的 dataSource
。
provider2DataSource.data = [2]
你还可以实时更新周围的部分。
finalProvider.sections = [provider2, provider3, provider1]
或者添加更多。
finalProvider.sections.append(provider4)
你甚至可以将 ComposedProvider
放入另一个 ComposedProvider
中,不会有问题。
let trulyFinalProvider = ComposedProvider(sections: [finalProvider, provider5])
collectionView.provider = trulyFinalProvider
这有多酷!
动画
CollectionKit 提供了一个动画系统,允许您创建复杂的动画,并调整单元格的显示方式。
以下是在示例项目中包含的一些自定义动画器示例。它们可以与任何布局结合使用。这里我们使用了转置的瀑布流布局。
摇摆 | 边缘收缩 | 缩放 |
---|---|---|
动画器还可以在单元格添加/移动/删除时执行动画。以下是一个显示3D缩放动画及其级联效果的示例。
使用 Animator
很简单。您可以将它分配给提供者、单元格或整个 CollectionView
。
// apply to the entire CollectionView
collectionView.animator = ScaleAnimator()
// apply to a single section, will override CollectionView's animator
provider.animator = FadeAnimator()
// apply to a single view, will take priority over all other animators
view.collectionAnimator = WobbleAnimator()
注意:要使用 WobbleAnimator
,您必须在 podfile 中包含 pod "CollectionKit/WobbleAnimator"
子规范。
请查看示例项目以查看这些示例如何实际运行。
有问题?想贡献?
加入我们的公共 Slack!