嵌入式视图控制器中的 UICollectionView 不会调用 cellForItemAtIndexPath

Posted

技术标签:

【中文标题】嵌入式视图控制器中的 UICollectionView 不会调用 cellForItemAtIndexPath【英文标题】:UICollectionView in embedded view controller does NOT call cellForItemAtIndexPath 【发布时间】:2015-01-28 22:04:05 【问题描述】:

我在一个视图中垂直嵌入了 2 个视图控制器。查看控制器 A(上传者)和 B(docList)。 B 包含一个 UICollectionView

所有,集合视图的数据源中除了 cellForItemAtIndexPath 之外的方法都被正确调用,我仔细检查了所有内容。有1节。行数超过 0 行。我返回的行的大小小于集合视图等

这是一个说明设置的图表:

我的问题是: 除非我将 setTranslatesAutoresizingMaskIntoConstraints 设置为 YES,否则永远不会调用 cellForItemAtIndexPath。如果我在 View Controller B 的视图上将该属性设置为 YES,那么它会被调用。但是布局被搞砸了,因为我没有使用弹簧和支柱。我们在这里只使用约束。

你知道嵌入包含 UICollectionView 的视图控制器时我会做错什么吗?

这是嵌入两个视图控制器的视图的代码,并将它们设置为子控制器:

 - (MFFormBaseCell *)cellForComponent
    
self.cell = [[MFFormBaseCell alloc] initWithFrame:CGRectZero];
[self.cell addSubview: uploader.view];
[self.cell addSubview: docList.view];

UIView* uploaderView = uploader.view;
UIView* docListView = docList.view;

NSMutableArray* tempConstraints = [[NSMutableArray alloc]init];

[tempConstraints addObjectsFromArray:
     [NSLayoutConstraint constraintsWithVisualFormat: @"V:|-8-[uploaderView]-1-[docListView]-8-|"
                                             options: NSLayoutFormatDirectionLeadingToTrailing metrics:nil
                                               views: NSDictionaryOfVariableBindings(uploaderView, docListView)]];


[tempConstraints addObjectsFromArray:
 [NSLayoutConstraint constraintsWithVisualFormat: @"H:|-[uploaderView]-|"
                                         options: NSLayoutFormatDirectionLeadingToTrailing metrics:nil
                                           views: NSDictionaryOfVariableBindings(uploaderView)]];

[tempConstraints addObjectsFromArray:
 [NSLayoutConstraint constraintsWithVisualFormat: @"H:|-[docListView]|"
                                         options: NSLayoutFormatDirectionLeadingToTrailing metrics:nil
                                           views: NSDictionaryOfVariableBindings(docListView)]];

uploaderConstraints = [tempConstraints copy];
[self.cell addConstraints: uploaderConstraints];

[self.embedder addChildViewController:uploader];
[uploader didMoveToParentViewController:self.embedder];



[self.embedder addChildViewController:docList];
[docList didMoveToParentViewController:self.embedder];
docList.view.frame = self.cell.bounds;


return self.cell;


这里是来自 View Controller B 的代码,它设置了 UICollectionView 和一个垂直流布局。

- (void)modelDidLoad


    _dataSource = [[MFCardDataSource alloc] initWithData: self.cardModel];;

    UICollectionViewFlowLayout *aFlowLayout = [[UICollectionViewFlowLayout alloc] init];


    [aFlowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];

    _collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:aFlowLayout];
    [_collectionView setDelegate: self];
    [_collectionView setDataSource:_dataSource];
    [_collectionView setBackgroundColor:[UIColor clearColor]];

    for (NSString* type in [MFCardCollectionModel typeArray])
        [_collectionView registerClass:[MFImageCard class] forCellWithReuseIdentifier: type];

    [_collectionView setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:_collectionView];

    [self registerConstraintsForView:_collectionView];

    if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
        self.edgesForExtendedLayout = UIRectEdgeNone;

    [super modelDidLoad];


以及registerConstraintsForView的内容:

-(void) registerConstraintsForView:(UIView*)collectionView

    NSDictionary* metrics = @ @"padding": @PADDING  ;

    NSDictionary* views = NSDictionaryOfVariableBindings(_collectionView);
    [self.view addConstraints:[NSLayoutConstraint
                               constraintsWithVisualFormat:@"V:|-padding-[_collectionView]-padding-|"
                               options:NSLayoutFormatDirectionLeadingToTrailing
                               metrics:metrics
                               views:views]];

    [self.view addConstraints:[NSLayoutConstraint
                               constraintsWithVisualFormat:@"H:|-padding-[_collectionView]-padding-|"
                               options:NSLayoutFormatDirectionLeadingToTrailing
                               metrics:metrics
                               views:views]];

【问题讨论】:

我实际上发现问题是:Housing View Controller的框架(docList)太小了。所以 UICollectionView 有一些内部逻辑来检查外壳框架是否足够大以显示里面包含的内容。如果没有足够的高度/宽度来显示单元格,它不会调用 cellForItemAtIndexPath。我通过在视图控制器的视图上设置背景颜色发现了问题,并看到它只有 50 像素高。为该视图控制器的视图设置约束以指定更大的静态高度,解决了该问题。像这样:V:|-[docListView(==600)] 换句话说,包含的 UICollection 视图将不会返回其适当的intrinsicContentSize,并且不会导致其父级拉伸,因为如果容器的视图太小,它甚至不会开始绘制它的单元格渲染它们.... 【参考方案1】:

我通过子类化 UICollectionView 并改用子类解决了这个问题。

在子类上我覆盖了 2 个方法:

- (void) setContentSize:(CGSize)contentSize

    CGSize origSize = self.contentSize;
    [super setContentSize:contentSize];
    if (!CGSizeEqualToSize(contentSize, origSize))
    
        [self invalidateIntrinsicContentSize];
    


- (CGSize) intrinsicContentSize

    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height);

然后,我的视图控制器中有一个方法,其中包含集合视图,它计算集合视图所需的高度。 然后,我在 Collection View 的子类上使用计算出的高度调用 setContentSize,并确保它返回的intrinsicContentSize 与显示其中的所有卡片记录所需的高度一样高。

【讨论】:

以上是关于嵌入式视图控制器中的 UICollectionView 不会调用 cellForItemAtIndexPath的主要内容,如果未能解决你的问题,请参考以下文章

在嵌入在两个独立容器控制器中的视图之间实现委托

从嵌入在容器视图中的视图控制器中分离

如何从嵌入在视图控制器中的表视图中的集合视图中传递数据并推送新的视图控制器?

视图控制器中的集合视图,单元格触摸集合视图本身的顶部边框(嵌入在导航控制器中)

无法关闭嵌入在导航控制器中的两个视图控制器

加载嵌入在导航中的视图控制器