How do I know that the UICollectionView has been l

2019-01-08 09:17发布

I have to do some operation whenever UICollectionView has been loaded completely, i.e. at that time all the UICollectionView's datasource / layout methods should be called. How do I know that?? Is there any delegate method to know UICollectionView loaded status?

13条回答
我只想做你的唯一
2楼-- · 2019-01-08 09:31

It's actually rather very simple.

When you for example call the UICollectionView's reloadData method or it's layout's invalidateLayout method, you do the following:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.collectionView reloadData];
});

dispatch_async(dispatch_get_main_queue(), ^{
    //your stuff happens here
    //after the reloadData/invalidateLayout finishes executing
});

Why this works:

The main thread (which is where we should do all UI updates) houses the main queue, which is serial in nature, i.e. it works in the FIFO fashion. So in the above example, the first block gets called, which has our reloadData method being invoked, followed by anything else in the second block.

Now the main thread is blocking as well. So if you're reloadData takes 3s to execute, the processing of the second block will be deferred by those 3s.

查看更多
We Are One
3楼-- · 2019-01-08 09:34

Def do this:

//Subclass UICollectionView
class MyCollectionView: UICollectionView {

    //Store a completion block as a property
    var completion: (() -> Void)?

    //Make a custom funciton to reload data with a completion handle
    func reloadData(completion: @escaping() -> Void) {
        //Set the completion handle to the stored property
        self.completion = completion
        //Call super
        super.reloadData()
    }

    //Override layoutSubviews
    override func layoutSubviews() {
        //Call super
        super.layoutSubviews()
        //Call the completion
        self.completion?()
        //Set the completion to nil so it is reset and doesn't keep gettign called
        self.completion = nil
    }

}

Then call like this inside your VC

let collection = MyCollectionView()

self.collection.reloadData(completion: {

})

Make sure you are using the subclass!!

查看更多
你好瞎i
4楼-- · 2019-01-08 09:36

Do it like this:

       UIView.animateWithDuration(0.0, animations: { [weak self] in
                guard let strongSelf = self else { return }

                strongSelf.collectionView.reloadData()

            }, completion: { [weak self] (finished) in
                guard let strongSelf = self else { return }

                // Do whatever is needed, reload is finished here
                // e.g. scrollToItemAtIndexPath
                let newIndexPath = NSIndexPath(forItem: 1, inSection: 0)
                strongSelf.collectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
        })
查看更多
可以哭但决不认输i
5楼-- · 2019-01-08 09:37

Just to add to a great @dezinezync answer:

Swift 3+

collectionView.collectionViewLayout.invalidateLayout() // or reloadData()
DispatchQueue.main.async {
    // your stuff here executing after collectionView has been layouted
}
查看更多
做个烂人
6楼-- · 2019-01-08 09:39

As dezinezync answered, what you need is to dispatch to the main queue a block of code after reloadData from a UITableView or UICollectionView, and then this block will be executed after cells dequeuing

In order to make this more straight when using, I would use an extension like this:

extension UICollectionView {
    func reloadData(_ completion: @escaping () -> Void) {
        reloadData()
        DispatchQueue.main.async { completion() }
    }
}

It can be also implemented to a UITableView as well

查看更多
家丑人穷心不美
7楼-- · 2019-01-08 09:42

I needed some action to be done on all of the visible cells when the collection view get loaded before it is visible to the user, I used:

public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if shouldPerformBatch {
        self.collectionView.performBatchUpdates(nil) { completed in
            self.modifyVisibleCells()
        }
    }
}

Pay attention that this will be called when scrolling through the collection view, so to prevent this overhead, I added:

private var souldPerformAction: Bool = true

and in the action itself:

private func modifyVisibleCells() {
    if self.shouldPerformAction {
        // perform action
        ...
        ...
    }
    self.shouldPerformAction = false
}

The action will still be performed multiple times, as the number of visible cells at the initial state. but on all of those calls, you will have the same number of visible cells (all of them). And the boolean flag will prevent it from running again after the user started interacting with the collection view.

查看更多
登录 后发表回答