Collor:UICollectionView的面向MVVM数据的框架
问题
在oui.sncf(法国和欧洲的火车票预订主要应用程序)上,我们的主要工作是显示服务器发送给我们的内容,大多数视图也是动态的。 此外,该应用程序经常会更新为新功能,甚至静态视图也会不断发展。
因此,我们决定使用UICollectionView! 它功能强大,动态且可自定义。
但是,当有很多不同的项目时,例如在Voyages-sncf.com应用程序中,Apple的面向indexPath的实现可能会变得混乱。
代码重复,切换大小写,难以维护,更新期间存在indexPath错误的风险……
解
我们已经建立了一年的框架,以简化和加快这些UICollectionView屏幕的开发。 该库的主要目标是在一个文件中拥有一个可读的dataSource,它表示collectionView内容。
我们将其称为Collor , Coll [ ectionViewDescript] 或 。
https://github.com/voyages-sncf-technologies/Collor
科洛尔做了两件事:
- 首先,它提供了基于MVVM的可伸缩微体系结构,以组织代码并避免重复。
- 然后,它提供了一些功能,以便删除collectionView实现所需的许多代码,例如单元格注册等,并轻松更新collectionView:删除,插入,重新加载,比较等。
建筑
为了描述collectionView,一个collectionData对象,它继承自CollectionData
用来。 它分为部分和项目。
UICollectionView数据源要求collectionData知道节的数量,节中的项目数以及要出队的单元格。
collectionData对象包含一个SectionDescriptor数组:SectionDescriptor实现协议SectionDescribable
,并使用Apple的FlowLayout处理某些节功能,例如sectionInset
, minimumInteritemSpacing
和minimumLineSpacing
。 SectionDescriptor还包含一个CellDescriptor数组。
例如,在Voyages-sncf.com应用程序上,每次我们需要一个简单的标签单元时,我们只需创建一个新适配器即可实现VSCollectionLabelAdapter
协议, VSCollectionLabelAdapter
用UICollectionViewCell及其先前创建的描述符。
适配器管理标签的样式; 标签会使用Autolayout填充整个单元格,并使用NSAttributedString.boundingRect()
计算其高度。
一些代码来解释我们做了什么:
确实,您可能有一个描述符,该描述符以最小的变化处理相似的单元:左侧或右侧的图像。 因此将有两个单元,但是一个描述符和一个公共适配器协议。
Collor是一个面向协议的框架。 可以在示例中实现新协议BackgroundDrawable
,而不是在节描述符中添加属性,因此可以在其他自定义布局中重用…
协议BackgroundDrawable {
var backgroundInset:UIEdgeInsets {获取设置}
}
CollectionView更新
如果您已经必须在tableView或collectionView中实现扩展/折叠,那么Collor应该会让您感兴趣。
实际上, Collor提供了一些轻松添加,删除,重新加载节或项目的方法。 不再需要使用IndexPath
,您只需操纵描述符引用, Collor即可完成工作。 更新collectionData之后, Collor通过调用UICollectionView.performBatchUpdates(_:completion:)
或UICollectionView.performUpdates(with:completion:)
为您提供一个用于更新collectionView的结果对象。 数据和视图也始终与collectionView同步。
让result = myCollectionData.update {
updater.remove(cells:[cellDescriptor])
updater.append(sections:[blueSection],之后:lastSection!)
// ...
}
collectionView.performUpdates(带有:结果)
collectionData中的每个更新都必须包含在CollectionData.update(_:)
给出的闭包中
看看github上的pantone示例。
差异化
差异数据
使用Collor ,可以计算两个数据之间的差异。 Collor正在使用Jack Flintermann令人惊叹的Dwifft库来完成该任务。 如果您的数据包含条件显示,这将非常有用。
用几行代码计算两个数据状态之间的差异:
myModel.someChanges()
yourCollectionData.update(model:myModel)
让结果= yourCollectionData.update {更新
updater.diff()
}
collectionView.performUpdates(带有:结果)
要使用此功能,每个部分和每个项目都必须具有唯一的标识符,即字符串值:
让yellowSection = MainColorSectionDescriptor()。uid(“ yellowSection”)
让yellowTitle = TitleDescriptor(适配器:TitleAdapter(颜色:.yellow))。uid(“ yellowTitle”)
不同部分中的单元格可以具有相同的id,在计算差异时,单元格uid和其部分uid串联在一起。 在上一个示例中,yellowTitle uid是yellowSection / yellowTitle。
看看github上的随机样本。
区分部分
您可以在一个部分中进行一些更改。 例如,展开崩溃。 计算整个数据的差异毫无意义。
Collor提供了一项功能,可以仅计算某些部分中的差异:
sectionDescriptor.isExpanded =!sectionDescriptor.isExpanded
让结果= collectionData.update {更新
updater.diff(sections:[sectionDescriptor])
}
collectionView.performUpdates(带有:结果)
由于此功能,每个部分建筑物都被封闭在一个封闭中。 Collor也可以具有sectionDescriptor单元格数组的旧状态和新状态。
let section = MySectionDescriptor()。reloadSection {
cells.append(...)
}
看看github上的天气样本。
感谢您的阅读,并让我知道您在Twitter上的想法。