UICollectionView (Automatic Size) .reloadData() re

2019-04-09 02:09发布

问题:

I have a UICollectionView using a standard UICollectionViewFlowLayout with an estimatedItemSizeset to UICollectionViewFlowLayoutAutomaticSize.

Once I call collectionView.reloadData() the scroll position of the view resets to CGPoint(x: 0, y: 0). I know that .reloadData() should only be used as a last resort, it is necessary in my scenario though. I have found out so far that it is probably caused by not returning an item size through collectionView(_:layout:sizeForItemAt:). (Any solutions for that analogous to UITableView’s tableView:estimatedHeightForRowAtIndexPath: like in this StackOverflow answer would be highly appreciated).

回答1:

reloadData reloads all cells in your UICollectionView so if you have any reference to cells it will point to object that is not exist, and what's more if it's strong reference it may cause a retain cycle. So:

You should not do it!

But...

It's hard to imagine the scenario where reloadData is needed and it cannot be replaced by inserting and deleting objects.

So what you may want to use is reload single row or maybe insert items that it change in your data model. You didn't post what your problem is with details, but you can do any of this actions mentioned earlier like:

        collectionView.performBatchUpdates({
            collectionView.insertItems(at: <#T##[IndexPath]#>)
            collectionView.deleteItems(at: <#T##[IndexPath]#>)
            collectionView.reloadItems(at: <#T##[IndexPath]#>)
        }, completion: { (<#Bool#>) in
            <#code#>
        })

But make sure you'll edit your data model first. So:

var dataModel: [String] = ["0","1","2"]   //Data model for Collection View
collectionView.reloadData() // In that point you will have 3 cells visible on the sceen
.
.
.
dataModel.removeFirst() // now your data model is ["1","2"]
collectionView.performBatchUpdates({
    collectionView.deleteItems(at: [IndexPath(row: 0, section:0)])
}, completion: { success in 
    //some check consistency code
})

And with that, your collectionview will remain the same, and no other change will be made besides this first row.



回答2:

Not sure if it might work, but you can give a try :

    let currentOffset = self.collectionView.contentOffset
    self.collectionView.reloadData()
    self.collectionView.setContentOffset(currentOffset, animated: false)

Do lemme know. Thanks :)