重新加载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页眉或页脚?的主要内容,如果未能解决你的问题,请参考以下文章

如何从pdf文件中查找页眉页脚

如何将文本添加为 页眉或页脚?

我无法在 Monotouch UITableViewController 中禁用页眉或页脚

如何为我的 Android 应用程序创建页眉或页脚按钮栏

html5:使用页眉或页脚标签两次?

如何使用c ++自动化将页眉或页脚插入到Word文档中