我必须做一些操作,每当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回答,你需要的是后派遣到主队列的代码块reloadData
从UITableView
或UICollectionView
,然后这个块将细胞离队后执行
为了让使用时,这更直,我会用这样的扩展:
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;
}