更改数据源时,UICollectionView中的动画流畅

时间:2019-04-03 20:14:26

标签: ios swift animation uicollectionview

我有一个UISegmentControl,可用于切换UICollectionView的数据源。数据源是不同类型的对象。

例如,对象可能看起来像这样

struct Student {
    let name: String
    let year: String
    ...
}
struct Teacher {
    let name: String
    let department: String
    ...
}

在包含CollectionView的视图中,将有如下代码:

var students = [Student]()
var teachers = [Teachers]()
... // populate these with data via an API

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    if(segmentControl.titleForSegment(at: segmentControl.selectedSegmentIndex) == "Students") {
        return students?.count ?? 0
    } else {
        return teachers?.count ?? 0
    } 
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "personCell", for: indexPath) as! PersonCell
    if(segmentControl.titleForSegment(at: segmentControl.selectedSegmentIndex)! == "Students") {
        cell.title = students[indexPath.row].name
        cell.subtitle = students[indexPath.row].year
    } else {
        cell.title = teachers[indexPath.row].name
        cell.subtitle = teachers[indexPath.row].subject
    }
    return cell
}

@IBAction func segmentChanged(_ sender: AnyObject) {
    collectionView.reloadData()
}

这可以在两个数据源之间正确切换,但是不会使更改生效。我尝试过:

self.collectionView.performBatchUpdates({
    let indexSet = IndexSet(integersIn: 0...0)
    self.collectionView.reloadSections(indexSet)
}, completion: nil)

但这只是崩溃(我认为这是因为performBatchUpdates对要删除的内容和要添加的内容感到困惑)。

有没有一种简单的方法可以使这项工作顺利进行,而无需在collectionView中使用单独的数组存储当前项目,或者这是使这项工作顺利进行的唯一方法?

非常感谢!

1 个答案:

答案 0 :(得分:0)

如果您的Cell的UI从不同的数据源看起来只是相同的,则可以在数据源上抽象一个ViewModel,如下所示:

struct CellViewModel {
    let title: String
    let subTitle: String
    ...
}

然后,每次从API获取数据时,就动态生成ViewModel

    var students = [Student]()
    var teachers = [Teachers]()
    ... // populate these with data via an API

    var viewModel = [CellViewModel]()
    ... // populate it from data above by checking currently selected segmentBarItem

    if(segmentControl.titleForSegment(at: segmentControl.selectedSegmentIndex)! == "Students") {
        viewModel = generateViewModelFrom(students)
    } else {
        viewModel = generateViewModelFrom(teachers)
    }

因此,您始终使用UICollectionView保留一个数据源数组。

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return viewModel?.count ?? 0
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "personCell", for: indexPath) as! PersonCell
    cell.title = viewModel[indexPath.row].title
    cell.subtitle = viewModel[indexPath.row].subTitle
    return cell
}

@IBAction func segmentChanged(_ sender: AnyObject) {
    collectionView.reloadData()
}

然后尝试您的performBatchUpdates:

self.collectionView.performBatchUpdates({
    let indexSet = IndexSet(integersIn: 0...0)
    self.collectionView.reloadSections(indexSet)
}, completion: nil)