我怎么知道UICollectionView已经完全加载?(How do I know that th

2019-07-17 13:34发布

我必须做一些操作,每当UICollectionView已经完全加载,即在那个时候所有的UICollectionView的数据源/布局方法应该被调用。 我怎么知道? 是否有任何的委托方法知道UICollectionView加载状态?

Answer 1:

// In viewDidLoad
[self.collectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary  *)change context:(void *)context
{
    // You will get here when the reloadData finished 
}

- (void)dealloc
{
    [self.collectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];
}


Answer 2:

这为我工作:

[self.collectionView reloadData];
[self.collectionView performBatchUpdates:^{}
                              completion:^(BOOL finished) {
                                  /// collection-view finished reload
                              }];

斯威夫特4语法:

self.collectionView.reloadData()
self.collectionView.performBatchUpdates(nil, completion: {
    (result) in
    // ready
})


Answer 3:

这其实相当简单。

当您例如调用UICollectionView的reloadData方法或它的布局的方法的invalidateLayout,请执行以下操作:

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
});

为什么这个工程:

主线程(这是我们应该做的所有UI更新)房屋的主队列,这在本质上是串行的,即它工作在FIFO方式。 所以在上面的例子中,第一块被调用,其中有我们的reloadData方法被调用,然后在第二块别的。

现在,主线程阻塞以及。 所以,如果你reloadData需要三分来执行,第二块的处理将被本3S推迟。



Answer 4:

我想补充一个伟大@dezinezync答案:

斯威夫特3+

collectionView.collectionViewLayout.invalidateLayout() // or reloadData()
DispatchQueue.main.async {
    // your stuff here executing after collectionView has been layouted
}


Answer 5:

像这样做:

       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)
        })


Answer 6:

不同的使用RxSwift / RxCocoa接近:

        collectionView.rx.observe(CGSize.self, "contentSize")
            .subscribe(onNext: { size in
                print(size as Any)
            })
            .disposed(by: disposeBag)


Answer 7:

这对我的作品:

__weak typeof(self) wself= self;
[self.contentCollectionView performBatchUpdates:^{
    [wself.contentCollectionView reloadData];
} completion:^(BOOL finished) {
    [wself pageViewCurrentIndexDidChanged:self.contentCollectionView];
}];


Answer 8:

作为dezinezync回答,你需要的是后派遣到主队列的代码块reloadDataUITableViewUICollectionView ,然后这个块将细胞离队后执行

为了让使用时,这更直,我会用这样的扩展:

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

它也可以实现一个UITableView还有



Answer 9:

防守做到这一点:

//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
    }

}

然后调用你这样的VC里面

let collection = MyCollectionView()

self.collection.reloadData(completion: {

})

请确保您使用的是子类!



Answer 10:

我需要一些动作来所有可见单元格的时候做集合视图得到加载之前,它是对用户可见,我使用:

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

要注意的是通过收集视图滚动时,这将被调用,因此要防止这种开销,我说:

private var souldPerformAction: Bool = true

而在行动本身:

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

该操作将仍然被执行多次,作为在初始状态下可见细胞的数目。 但在所有这些电话,你将有相同数量的可见细胞(所有的)。 和布尔标志会阻止它再次运行的用户开始与集合视图交互之后。



Answer 11:

这项工作对我来说:


- (void)viewDidLoad {
    [super viewDidLoad];

    int ScrollToIndex = 4;

    [self.UICollectionView performBatchUpdates:^{}
                                    completion:^(BOOL finished) {
                                             NSIndexPath *indexPath = [NSIndexPath indexPathForItem:ScrollToIndex inSection:0];
                                             [self.UICollectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
                                  }];

}



Answer 12:

尝试强制通过layoutIfNeeded同步布局通()的reloadData()调用之后。 似乎两个UICollectionView和工作的UITableView在iOS上12。

collectionView.reloadData()
collectionView.layoutIfNeeded() 

// cellForItem/sizeForItem calls should be complete
completion?()


Answer 13:

这是我如何解决问题,雨燕3.0:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if !self.collectionView.visibleCells.isEmpty {
        // stuff
    }
}


Answer 14:

你可以这样做?

  - (void)reloadMyCollectionView{

       [myCollectionView reload];
       [self performSelector:@selector(myStuff) withObject:nil afterDelay:0.0];

   }

  - (void)myStuff{
     // Do your stuff here. This will method will get called once your collection view get loaded.

    }


Answer 15:

试试这个:

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return _Items.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell;
    //Some cell stuff here...

    if(indexPath.row == _Items.count-1){
       //THIS IS THE LAST CELL, SO TABLE IS LOADED! DO STUFF!
    }

    return cell;
}


文章来源: How do I know that the UICollectionView has been loaded completely?