本文基于IGListKit 4.0实现列表的高帧率滑动效果,项目地址见GitHub
话不多说,上图
创建基类控制器
所有IGListKit
的视图控制器都应该继承此类,减少复用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| class BaseListVC: UIViewController {
var objects: [ListDiffable] = [ListDiffable]()
lazy var collectionView: UICollectionView = { let flow = UICollectionViewFlowLayout() let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: flow) if #available(iOS 11.0, *) { collectionView.contentInsetAdjustmentBehavior = .never } else { automaticallyAdjustsScrollViewInsets = false } collectionView.backgroundColor = UIColor.groupTableViewBackground return collectionView }() lazy var adapter: ListAdapter = { let adapter = ListAdapter(updater: ListAdapterUpdater(), viewController: self) return adapter }()
override func viewDidLoad() { super.viewDidLoad() view.addSubview(collectionView) adapter.collectionView = collectionView adapter.dataSource = self }
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() collectionView.frame = view.bounds } }
extension BaseListVC : ListAdapterDataSource { func objects(for listAdapter: ListAdapter) -> [ListDiffable] { return objects }
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { return ListSectionController() }
func emptyView(for listAdapter: ListAdapter) -> UIView? { return nil } }
|
创建MomentInfo
模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class MomentInfo { var id: Int = 0 ... } extension MomentInfo: ListDiffable { func diffIdentifier() -> NSObjectProtocol { return id as NSObjectProtocol }
func isEqual(toDiffableObject object: ListDiffable?) -> Bool { guard self === object else { return true } guard let object = object as? MomentInfo else { return false } return id == object.id } }
extension MomentInfo: Equatable { static func == (lhs: MomentInfo, rhs: MomentInfo) -> Bool { return lhs.isEqual(toDiffableObject: rhs) } }
|
子类复写
- 更新数据
1 2 3 4
| self.objects.append(info)
self.adapter.performUpdates(animated: true, completion: nil)
|
- 复写绑定Section
1 2 3 4 5 6 7 8 9 10 11
| override func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { switch object { case is MomentInfo: let section = MomentBindingSection() return section default: fatalError() } }
|
使用ListBindingSectionController
绑定多个cell
- 创建
UICollectionViewCell
⚠️只能有一种样式布局,不同样式需要不同的cell
1 2 3 4 5 6 7 8 9
| class MomentTopCell: UICollectionViewCell { ... } extension MomentTopCell: ListBindable { func bindViewModel(_ viewModel: Any) { guard let viewModel = viewModel as? MomentInfo else { return } } }
|
- 获取cell对象
1 2 3 4 5 6 7
| func momentTopCell(at index: Int) -> MomentTopCell {
guard let cell = collectionContext?.dequeueReusableCell(of: MomentTopCell.self, for: self, at: index) as? MomentTopCell else { fatalError() } cell.bindViewModel(object!) return cell }
|
- 绑定视图模型(ViewModel),可使用枚举替代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| enum ViewModelEnum: String { case top, header, image_single, location, bottom }
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, viewModelsFor object: Any) -> [ListDiffable] { guard let object = object as? MomentInfo else { return [] } var results: [ListDiffable] = [] if object.userInfo != nil { results.append(ViewModelEnum.top.rawValue as ListDiffable) } if object.images.count == 1 { results.append(ViewModelEnum.image_single.rawValue as ListDiffable) }else { results.append(ViewModelEnum.header.rawValue as ListDiffable) } if !object.location.isEmpty { results.append(ViewModelEnum.location.rawValue as ListDiffable) } results.append(ViewModelEnum.bottom.rawValue as ListDiffable) return results }
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, cellForViewModel viewModel: Any, at index: Int) -> UICollectionViewCell & ListBindable { let viewModel = ViewModelEnum(rawValue: viewModel as! String)! switch viewModel { case .top: return momentTopCell(at: index) case .image_single: return momentHeaderImageCell(at: index) case .header: return momentHeaderCell(at: index) case .location: return momentLocationCell(at: index) case .bottom: return momentBottomCell(at: index) } }
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, sizeForViewModel viewModel: Any, at index: Int) -> CGSize { guard let object = object as? MomentInfo else { fatalError() } let viewModel = ViewModelEnum(rawValue: viewModel as! String)! let width: CGFloat = collectionContext!.containerSize(for: self).width switch viewModel { case .top: return CGSize(width: width, height: 400) case .header, .image_single: return CGSize(width: width, height: object.cellHeight) case .location: return CGSize(width: width, height: 30) case .bottom: return CGSize(width: width, height: 30) } }
|