我有一些数据,是在另一个线程更新一个UICollectionView的头取出。 但是,我还没有发现重装补充视图,如页眉或页脚的有效方式。
我可以调用collectionView reloadSections:
但这种重装整款是不必要的。 collectionView reloadItemsAtIndexPaths:
似乎只对靶细胞(没有补充意见)。 并呼吁setNeedsDisplay
在标题本身似乎并没有擦出火花。 我缺少的东西吗?
我有一些数据,是在另一个线程更新一个UICollectionView的头取出。 但是,我还没有发现重装补充视图,如页眉或页脚的有效方式。
我可以调用collectionView reloadSections:
但这种重装整款是不必要的。 collectionView reloadItemsAtIndexPaths:
似乎只对靶细胞(没有补充意见)。 并呼吁setNeedsDisplay
在标题本身似乎并没有擦出火花。 我缺少的东西吗?
您也可以使用(偷懒的方法)
collectionView.collectionViewLayout.invalidateLayout() // swift
[[_collectionView collectionViewLayout] invalidateLayout] // objc
更复杂的是提供一个上下文
collectionView.collectionViewLayout.invalidateLayout(with: context) // swift
[[_collectionView collectionViewLayout] invalidateLayoutWithContext:context] // objc
然后,您可以做一个或配置方面自己告知应该怎样更新参阅: UICollectionViewLayoutInvalidationContext
它在那里,你可以覆盖一个函数:
invalidateSupplementaryElements(ofKind:at:) // swift
我只是碰到了同样的问题,我结束了使用它的标签编辑标签查找的观点:
UICollectionReusableView *footer = (UICollectionReusableView*)[self.collectionView viewWithTag:999];
UILabel *footerLabel = (UILabel*)[footer viewWithTag:100];
就像你说的,不需要重新加载整个部分,它消除了对细胞的任何动画,以及。 我的解决方案并不理想,但它是很容易做到。
我得到了同样的问题。 我试图@ BobVorks的答案,它工作正常,如果仅仅将电池重新使用别的也不会。 所以,我试图找到一个更清洁的方式来实现这一点,我想出了重装performBatchUpdate(完成块)后,整个UICollectionView,它是伟大的工作。 它重新加载收藏没有在insertItemsAtIndexPath动画的任何取消。 其实我个人投了近2个回答,因为我觉得它的工作,但在我而言,这是做的最彻底的方法。
[self.collectionView performBatchUpdates:^{
// perform indexpaths insertion
} completion:^(BOOL finished) {
[self.collectionView reloadData];
}];
斯威夫特3/4版本:
collectionView.collectionViewLayout.invalidateLayout()
警告!
如果更改数量collectionView
在同一时间的项目(例如,你只显示如果加载的所有单元格的页脚),它会崩溃 。 首先,您需要重新加载数据,以确保项目的数量是相同的之前和之后invalidateLayout()
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
这里有两种方法可以做到这一点。
1.创建一个可变模型来备份数据,最终将可用。 使用国际志愿者组织在继承类UICollectionReusableView的观察其变化,并因为它来自可更新为新数据的标题视图。
[model addObserver:headerView
forKeyPath:@"path_To_Header_Data_I_care_about"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
然后实现在头部视图侦听方法
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
2.添加通知监听器查看和发布通知时,数据已成功来获得。 缺点是,这是应用广泛,而不是一个干净的设计。
// place in shared header file
#define HEADER_DATA_AVAILABLE @"Header Data Available Notification Name"
// object can contain userData property which could hole data needed.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(headerDataAvailable:) name:HEADER_DATA_AVAILABLE object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:HEADER_DATA_AVAILABLE object:nil];
[UIView performWithoutAnimation:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:4]];
}];
[UIView performWithoutAnimation:^{
[self.collectionView reloadData];
}];
这里就是我所做的只更新当前加载在内存中的节标题:
NSMapTable
。 当你创建一个标题,添加标题为弱保持的关键,与indexPath对象。 如果我们重新使用标头,我们将更新indexPath。 NSMapTable
需要。
@interface YourCVController ()
@property (nonatomic, strong) NSMapTable *sectionHeaders;
@end
@implementation YourCVContoller
- (void)viewDidLoad {
[super viewDidLoad];
// This will weakly hold on to the KEYS and strongly hold on to the OBJECTS
// keys == HeaderView, object == indexPath
self.sectionHeaders = [NSMapTable weakToStrongObjectsMapTable];
}
// Creating a Header. Shove it into our map so we can update on the fly
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
PresentationSectionHeader *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"presentationHeader" forIndexPath:indexPath];
// Shove data into header here
...
// Use header as our weak key. If it goes away we don't care about it
// Set indexPath as object so we can easily find our indexPath if we need it
[self.sectionHeaders setObject:indexPath forKey:header];
return header;
}
// Update Received, need to update our headers
- (void) updateHeaders {
NSEnumerator *enumerator = self.sectionHeaders.keyEnumerator;
PresentationSectionHeader *header = nil;
while ((header = enumerator.nextObject)) {
// Update the header as needed here
NSIndexPath *indexPath = [self.sectionHeaders objectForKey:header];
}
}
@end
这个问题是很老,但一个简单的方法来做到这一点是刚才设置涵盖的时间你的观点是动画和禁用动画,而你更新视图...通常是删除或插入大约需要0.35秒所以只是延迟做:
delay(0.35){
UIView.performWithoutAnimation{
self.collectionView.reloadSections(NSIndexSet(index: 1))
}
我的问题出现了,当帧尺寸的补充意见后无效布局而改变。 看来 ,补充意见不清爽。 原来,他们是的,但我正在建的UICollectionReusableView
编程对象,我没有删除旧UILabel
子视图。 因此,当集合视图离队每个标题来看,UILabels会堆积起来,造成不稳定的外观。
该解决方案是构建每个UICollectionReusableView完全内部viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
方法中,通过一开始)从所述出队的细胞除去所有子视图,然后b)获得从所述项目的布局属性框的大小允许添加新的子视图。
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
yourClass *header = (yourClass *)[collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"identifier" forIndexPath:indexPath];
[[header viewWithTag:1] removeFromSuperview]; // remove additional subviews as required
UICollectionViewLayoutAttributes *attributes = [collectionView layoutAttributesForSupplementaryElementOfKind:kind atIndexPath:indexPath];
CGRect frame = attributes.frame;
UILabel *label = [[UILabel alloc] initWithFrame: // CGRectMake based on header frame
label.tag = 1;
[header addSubview:label];
// configure label
return header;
}