【问题标题】:UICollectionView and Supplementary View (header)UICollectionView 和补充视图(标题)
【发布时间】:2013-02-20 04:37:27
【问题描述】:

尝试在我的UICollectionView 中添加一个补充视图作为标题。我在让它工作时遇到问题。

我使用自定义UICollectionViewFlowLayout 来返回一个contentSize,它总是至少比框架大1 个像素(我使用的是UIFreshControl,它仅在UICollectionView 滚动并设置@987654326 时才有效@ 直接什么都不做)和 invalidateLayout 上的 sectionInsertitemSize 变化:

-(void)setSectionInset:(UIEdgeInsets)sectionInset {
    if (UIEdgeInsetsEqualToEdgeInsets(super.sectionInset, sectionInset)) {
        return;
    }

    super.sectionInset = sectionInset;

    [self invalidateLayout];

}

-(void) setItemSize:(CGSize)itemSize {
    if (CGSizeEqualToSize(super.itemSize, itemSize)) {
        return;
    }

    super.itemSize = itemSize;

    [self invalidateLayout];
}

- (CGSize)collectionViewContentSize
{
    CGFloat height = [super collectionViewContentSize].height;

    // Always returns a contentSize larger then frame so it can scroll and UIRefreshControl will work
    if (height < self.collectionView.bounds.size.height) {
        height = self.collectionView.bounds.size.height + 1;
    }

    return CGSizeMake([super collectionViewContentSize].width, height);
}

我创建了一个UICollectionReusableView 类,它只是一个带有UILabelUIView

@implementation CollectionHeaderView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"CollectionHeaderView" owner:self options:nil];

        if ([arrayOfViews count] < 1) {
            return nil;
        }

        if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
            return nil;
        }

        self = [arrayOfViews objectAtIndex:0];

        self.headerLabel.text = @"This is a header. There are many like it.";
        self.backgroundColor = [UIColor yellowColor];


    }
    return self;
}

尝试实现它:

DatasetLayout *collectionViewFlowLayout = [[DatasetLayout alloc] init];
collectionViewFlowLayout.itemSize = CGSizeMake(360, 160);
collectionViewFlowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
collectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16);
collectionViewFlowLayout.minimumInteritemSpacing = 16;
collectionViewFlowLayout.minimumLineSpacing = 16;
collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100);

UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewFlowLayout];
collectionView.translatesAutoresizingMaskIntoConstraints = FALSE;
collectionView.backgroundColor = [UIColor yellowColor];
collectionView.delegate = self;
collectionView.dataSource = self;

我注册了课程:

[self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

并实现委托:

-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {

    CollectionHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView" forIndexPath:indexPath];

    headerView.headerLabel.text = @"Blarg!";

    return headerView;
}

线

collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100);

导致错误:

*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:], /SourceCache/UIKit_Sim/UIKit-2380.17/UICollectionView.m:1150
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'

如果我将其注释掉,它会运行但没有标题。

我做错了什么或没有实施?

【问题讨论】:

  • 错误是抱怨“未设置 UICollectionView 数据源”。 – collectionView:viewForSupplementaryElementOfKind:atIndexPath: 实际上是数据源协议方法而不是委托协议方法。你有集合视图集的 dataSource 属性吗?
  • 我不确定您所说的“集合视图集的 dataSource 属性?”是什么意思?我有一个数据源,如果我不尝试做标题,就会显示出来。
  • UICollectionView 对象有一个 dataSource 属性。您收到的错误是您尚未将其设置为将实现 – collectionView:viewForSupplementaryElementOfKind:atIndexPath: 方法的对象
  • 你在说collectionView.datasource = self;吗?

标签: ios objective-c uicollectionview uicollectionviewlayout


【解决方案1】:

一个iOS9的bug,在viewcontroller的dealloc set layer delegate nil.

- (void)dealloc{

    if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"9"]) {
        self.collectionView.layer.delegate = nil;
    }
}

【讨论】:

    【解决方案2】:

    我一直收到同样的错误。我已经为我的 collectionView 设置了 CustomHeaderView。我在我的 CustomHeaderView 中有一个 Collection Reusable View 类,并且我已经设置了标识符。我花了 1/2 小时试图找出失败的原因。

    由于未捕获的异常而终止应用程序 'NSInternalInconsistencyException',原因:'无法出列视图 种类:带有标识符的 UICollectionElementKindSectionFooter SectionHeader - 必须为标识符注册一个 nib 或一个类,或者 连接故事板中的原型单元'

    您需要仔细阅读日志...吸取教训。

    '无法使视图出队 种类:UICollectionElementKindSectionFooter

    原因是因为在情节提要中 - 在 collectionView 身份检查器中,我检查了两个附件:部分页眉和部分页脚。我只需要节标题。只需取消选中页脚...构建并运行..BOOM!

    【讨论】:

      【解决方案3】:

      此答案类似于您创建检查数据源的方法的其他答案,但它更简单一些。似乎这个问题与集合发布后集合视图的布局有关。所以我将布局的属性归零如下,错误消失了。

      deinit {
          let layout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
          layout.estimatedItemSize = CGSizeZero
          layout.sectionInset = UIEdgeInsetsZero
          layout.headerReferenceSize = CGSizeZero
      }
      

      【讨论】:

      • 你能确认这是一个错误还是我们遗漏了什么?
      • 这绝对是某个级别的错误 - 可能只是在文档中。通常当我向 Apple 提交这样的错误(你应该这样做)时,我会说预期值应该不同“或者文档应该更清晰”
      【解决方案4】:

      试试这个:

      self.collectionView?.dataSource = nil
      self.collectionView = nil
      

      它对我有用;)

      【讨论】:

        【解决方案5】:

        这个主题的答案很老了,在 iOS8 和 iOS9 中不起作用。如果您仍然遇到上述问题,请查看以下主题:UICollectionView and Supplementary View crash

        编辑

        这里是答案,以防链接失效:

        如果您在集合视图中使用自定义布局,请检查其数据源是否为 nil:

        - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
        

        结果应该是这样的:

        - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
            if (self.collectionView.dataSource != nil) {
                // Your layout code    
                return array;
            }
            return nil;
        }
        

        此更改解决了以下问题:

        • -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:] 中的断言失败

        您还可以检查以下主题,但在我的情况下它没有解决任何问题:

        Removing empty space, if the section header is hidden in the UICollectionView

        希望对你有所帮助,你不会像我一样浪费时间。

        【讨论】:

        • @ChrisLoonam - 给你
        【解决方案6】:

        我遇到了同样的问题,同样,我没有正确注册标题。这里有几个线程都建议使用 Nib 来定义标题,但我做了不同的事情并且工作正常。

        我有一个自定义标头 SizeCollectionHeader,它继承了 UICollectionReusableView。它是这样注册的。

            [self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"UICollectionElementKindSectionHeader"
                                                                                     withReuseIdentifier:@"SupplementaryViewIdentifier"];
        

        并且工作正常。

        我最初的问题是有一个像这样的随机“Kind”值。

            [self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"SupplementaryViewKind"
                                                                                     withReuseIdentifier:@"SupplementaryViewIdentifier"];
        

        这会崩溃。

        所以我只是想为任何正在查看这里的人发表评论,您不需要使用笔尖。

        【讨论】:

          【解决方案7】:

          我也遇到了这个烦人的错误:

          *** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-3347.44/UICollectionView.m:1400
          *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'
          

          我发现有些人通过这样做来解决这个错误

          - (void)dealloc {
              self.collectionView = nil;
          }
          

          或迅速:

          deinit {
              collectionView = nil
          }
          

          但是这些都没有解决我的崩溃问题。 我尝试了一些方法,下面的“hack”解决了这个烦人的错误:

          func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
              if collectionView.dataSource != nil {
                  return someHeaderSize
              } else {
                  return CGSizeZero
              }
          }
          

          【讨论】:

            【解决方案8】:

            我遇到了类似的问题,但是在我以编程方式弹出 UICollectionViewController 后,我的应用程序崩溃了。出于某种原因(我认为这只是 SDK 中的一个错误)self.collectionView 在其控制器销毁后仍然存在,从而导致此故障:

            *** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-2935.137/UICollectionView.m:1305
            *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'
            

            解决方案只是覆盖 UICollectionViewController 中的 -dealloc 并手动释放 self.collectionView。弧码:

            - (void)dealloc {
            
                self.collectionView = nil;
            }
            

            希望这会为某人节省时间。

            【讨论】:

            • 遇到了同样的问题。绝对看起来像是 SDK 中的错误。对我来说只发生在 iOS 8 中。
            • 使用 7.1.2 iPhone 4 获得它。
            • 你不应该在dealloc方法中使用访问器
            • 有什么快速的解决方案吗?
            • @MuhammadAsyraf 尝试 func deinit() { collectionView = nil }
            【解决方案9】:

            我清理了我的代码并删除了我在 IB 中创建的 UICollectionView,并在代码中创建了它。我再次运行它并得到一个不同的错误并意识到我没有在 IB 中设置委托或数据源。我做到了:

            self.collectionView.delegate = self;
            self.collectionView.datasource = self;
            

            但这肯定还不够好。

            因此,在 IB 中创建 UICollectionView,而不是在 IB 中设置 delgate/datasource,而是在代码中:

            [self.view bringSubviewToFront:self.collectionView];
            self.collectionView.collectionViewLayout = collectionViewFlowLayout;
            self.collectionView.backgroundColor = [UIColor orangeColor];
            self.collectionView.delegate = self;
            self.collectionView.dataSource = self;
            
            [self.collectionView registerClass:[DatasetCell class] forCellWithReuseIdentifier:@"cvCell"];
            
            [self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
            

            是个问题。我重做了它以在代码中创建 UICollectionView:

            UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewFlowLayout];
            collectionView.translatesAutoresizingMaskIntoConstraints = FALSE;
            collectionView.backgroundColor = [UIColor yellowColor];
            collectionView.delegate = self;
            collectionView.dataSource = self;
            
            [collectionView registerClass:[DatasetCell class] forCellWithReuseIdentifier:@"cvCell"];
            
            [collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
            
            [self.view addSubview:collectionView];
            
            self.collectionView = collectionView;
            

            我得到一个不同的错误:

            *** Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2380.17/UICollectionView.m:2249
            *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindSectionHeader with identifier CollectionHeaderView - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
            

            我会试着弄清楚。

            编辑:

            想通了,我错误地注册了标题:

            [collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
            

            切换到:

            UINib *headerNib = [UINib nibWithNibName:@"CollectionHeaderView" bundle:nil];
            
            [collectionView registerNib:headerNib forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
            

            一切正常。不完全确定 registerClass: 是如何工作的。

            【讨论】:

              【解决方案10】:

              如果您查看错误消息,它表示未设置数据源。这应该可以解决它:

              self.collectionView.dataSource = self;

              确保您的视图控制器实现数据源协议:

              YourViewController : UIViewController&lt;UICollectionViewDataSource&gt;

              【讨论】:

              • 我添加了我的 UICollectionView 实现,我确实将数据源设置为 self。
              • 我确实包括了代表,我想我找到了问题
              猜你喜欢
              • 2015-12-22
              • 2017-07-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-10-03
              • 1970-01-01
              • 2015-06-16
              相关资源
              最近更新 更多