重新加载UICollectionView页眉或页脚?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重新加载UICollectionView页眉或页脚?相关的知识,希望对你有一定的参考价值。
我有一些数据是在另一个更新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
另一个选项是(如果您已经加载了正确的页眉/页脚/补充视图),并且您只想使用新数据更新视图,而不是使用以下某个函数来检索它:
supplementaryView(forElementKind:at:) // get specific one
visibleSupplementaryViews(ofKind:) // all visible ones
对于具有visibleCells
的可见细胞也是如此。仅获取视图而不是完全重新加载视图的优点是细胞保持状态。当使用滑动删除/编辑/等时,这对于表视图单元格来说是很好的,因为在重新加载单元格后该状态会丢失。
如果您感到狂热,您当然也可以编写一些扩展来使用泛型来检索给定类型的单元格/补充视图
if let view = supplementaryView(forType: MySupplementaryView.self, at: indexPath) {
configure(view, at indexPath)
}
这假设您有一个函数,用于在示例中注册/取消其类名称的视图。我发了一篇关于这个here的帖子
let headerView = collectionView.visibleSupplementaryViews(ofKind: UICollectionView.elementKindSectionHeader)[0] as! UICollectionReusableView
我已经使用上面的方法获取当前标头,并成功更新了它的子视图。
我刚遇到同样的问题,最后我用标签查找视图来编辑标签:
UICollectionReusableView *footer = (UICollectionReusableView*)[self.collectionView viewWithTag:999];
UILabel *footerLabel = (UILabel*)[footer viewWithTag:100];
就像你说的那样,没有必要重新加载整个部分,这也取消了细胞上的任何动画。我的解决方案并不理想,但它很容易。
我遇到了同样的问题。我尝试了@ BobVorks的答案,它工作正常,如果只重复使用单元格,否则它不会。所以,我尝试找到一种更清晰的方法来实现这一点,然后我在performBatchUpdate(完成块)之后重新加载整个UICollectionView,它运行良好。它会重新加载Collection而不会在insertItemsAtIndexPath中取消任何动画。实际上我个人最近投了2个答案,因为我觉得它有效但在我的情况下,这是最干净的方法。
[self.collectionView performBatchUpdates:^{
// perform indexpaths insertion
} completion:^(BOOL finished) {
[self.collectionView reloadData];
}];
[UIView performWithoutAnimation:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:4]];
}];
[UIView performWithoutAnimation:^{
[self.collectionView reloadData];
}];
Swift 3/4/5版本:
collectionView.collectionViewLayout.invalidateLayout()
警告!
如果同时更改collectionView
项目的数量(例如,只有在加载了所有单元格时才显示页脚),它将崩溃。您需要先重新加载数据,以确保invalidateLayout()
之前和之后的项目数相同:
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
这有两种方法可以做到。
1.创建一个可变模型来支持最终可用的数据。在继承的UICollectionReusableView类中使用KVO来观察更改并使用新数据更新标头视图。
[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];
以下是我只更新当前在内存中加载的节标题的操作:
- 添加一个weakToStrong
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会堆积起来,导致外观不稳定。
解决方案是在viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
方法内完全构建每个UICollectionReusableView,首先a)从出列单元格中删除所有子视图,然后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;
}
以上是关于重新加载UICollectionView页眉或页脚?的主要内容,如果未能解决你的问题,请参考以下文章