如何获取iOS 8中UICollectionViewCells的自动布局大小?(systemLayoutSizeFittingSize在iOS 8中返回高度为零的尺寸)

24

自从iOS 8以来,[UICollectionViewCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] 返回的高度为0。

以下是代码的作用:

在iOS 7中,为了确定UICollectionView中单元格的大小,我使用了xib文件中基于自动布局的单元格上的systemLayoutSizeFittingSize:。这个大小取决于在我的xib文件中作为UICollectionViewCell子视图的UILabel的字体大小。标签的字体设置为UIFontTextStyleBody。因此,基本上单元格的大小取决于在iOS 7中进行的字体大小设置。

以下是代码本身:

+ (CGSize)cellSize {
    UINib *nib = [UINib nibWithNibName:NSStringFromClass([MyCollectionViewCell class]) bundle:nil];

    // Assumption: The XIB file only contains a single root UIView.
    UIView *rootView = [[nib instantiateWithOwner:nil options:nil] lastObject];

    if ([rootView isKindOfClass:[MyCollectionViewCell class]]) {
        MyCollectionViewCell *sampleCell = (MyCollectionViewCell*)rootView;
        sampleCell.label.text = @"foo"; // sample text without bar

        [sampleCell setNeedsLayout];
        [sampleCell layoutIfNeeded];

        return [sampleCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    }

    return CGSizeZero;

}

在iOS 7中它完美运作,但在iOS 8中却不行。很遗憾,我不知道为什么。

如何在iOS 8中获得UICollectionViewCells的自动布局大小?

PS:使用

 return [sampleCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

取代

 return [sampleCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

就像有些人可能会建议的那样,这没有任何区别。


仍未在Xcode 6 Beta 7上修复。 - ynnckcmprnl
经过进一步的测试,当使用Xcode 6 GM构建时,它似乎可以在iOS8 GM上工作。 - ynnckcmprnl
对我而言,Xcode 6 GM 在 iOS 8 下可以工作,但在 iOS 7 下返回 0!=( - Adlai Holler
@AdlaiHoller 我也遇到了完全相同的问题!如果你找到解决方案,请在这里更新。如果它影响iOS 7,那么这是否是XCode的错误而不是iOS 8 GM的错误? - Blake
我在另一个线程中找到了解决方法:https://dev59.com/-GAf5IYBdhLWcg3wVxjh - mariusLAN
显示剩余7条评论
8个回答

8
您需要做的是将所有内容包装在容器视图中,然后调用以下代码:
return [sampleCell.containerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

你的单元格应该像这样:单元格 -> 容器视图 -> 子视图。
在iOS7和iOS8上都可以使用此方法。
据说在iOS8上,只需要设置estimateSize,单元格就会自动调整大小。但是据说到beta 6时还不起作用。

虽然看起来很奇怪,但容器视图完全可以工作:我猜他们在UICollectionViewCell中弄坏了什么:S - tim harrison

7

看起来这是一个官方的错误:我提交了一份报告,被关闭作为这个的重复。

等到Beta 6发布后再回报。

[更新:在iOS 8 GM种子版本中已经正常工作,并且该错误已被苹果关闭。]


@maremmle,即使是重复的问题,您也应该提交错误报告。重复的错误报告会提高特定错误在苹果公司中的可见性,从而更有可能尽早得到解决。 - memmons
1
@MichaelG.Emmons 好的,我也向苹果提交了一个错误报告。 - martn_st
1
我的错误报告也被标记为17962954的重复。http://openradar.appspot.com/search?query=17962954 - ynnckcmprnl
@PhilipMcDermott,您能否报告iOS 8 GM上是否已修复? - kernix
事实上,我过于草率地得出了结论。它在iOS8 GM中可以工作,我还在单元格上调用了systemLayoutSizeFittingSize方法。 - ynnckcmprnl
显示剩余6条评论

4
我们目前使用的是一个解决方法,如下所示。希望在iOS 8发布之前这些问题得到解决,我们就可以将其删除了。(这个方法假定您知道苹果的implicit contentView行为,并且我们必须对任何我们传输的约束进行hack IB outlet引用。)
我们注意到他们在升级期间还从storyboards/NIBs中移除了所有的autoresizingMasks,这是有道理的,因为它应该是自动布局,但是集合视图仍然回退到springs & struts。也许这在清除时被忽视了?
- Dan
/**
 Kludge around cell sizing issues for iOS 8 and deployment to iOS 7 when compiled for 8.  Call this on the collection view cell before it is used, such as in awakeFromNib.  Because this manipulates top-level constraints, any references to such initial constraints, such as from IB outlets, will be invalidated.

 Issue 1: As of iOS 8 Beta 5, systemLayoutSizeFittingSize returns height 0 for a UICollectionViewCell.  In IB, cells have an implicit contentView, below which views placed in IB as subviews of the cell are actually placed.  However, constraints set between these subviews and its superview are placed on the cell, rather than the contentView (which is their actual superview).  This should be OK, as a constraint among items may be placed on any common ancestor of those items, but this is not playing nice with systemLayoutSizeFittingSize.  Transferring those constraints to be on the contentView seems to fix the issue.

 Issue 2: In iOS 7, prior to compiling against iOS 8, the resizing mask of the content view was being set by iOS to width+height.  When running on iOS 7 compiled against iOS 8 Beta 5, the resizing mask is None, resulting in constraints effecting springs for the right/bottom margins.  Though this starts out the contentView the same size as the cell, changing the cell size, as we do in the revealing list, is not tracked by changing it's content view.  Restore the previous behavior.

 Moving to dynamic cell sizing in iOS 8 may circumvent this issue, but that remedy isn't available in iOS 7.
*/
+ (void)kludgeAroundIOS8CollectionViewCellSizingIssues:(UICollectionViewCell *)cell {

    // transfer constraints involving descendants on cell to contentView
    UIView *contentView = cell.contentView;
    NSArray *cellConstraints = [cell constraints];
    for (NSLayoutConstraint *cellConstraint in cellConstraints) {
        if (cellConstraint.firstItem == cell && cellConstraint.secondItem) {
            NSLayoutConstraint *parallelConstraint = [NSLayoutConstraint constraintWithItem:contentView attribute:cellConstraint.firstAttribute relatedBy:cellConstraint.relation toItem:cellConstraint.secondItem attribute:cellConstraint.secondAttribute multiplier:cellConstraint.multiplier constant:cellConstraint.constant];
            parallelConstraint.priority = cellConstraint.priority;
            [cell removeConstraint:cellConstraint];
            [contentView addConstraint:parallelConstraint];
        } else if (cellConstraint.secondItem == cell && cellConstraint.firstItem) {
            NSLayoutConstraint *parallelConstraint = [NSLayoutConstraint constraintWithItem:cellConstraint.firstItem attribute:cellConstraint.firstAttribute relatedBy:cellConstraint.relation toItem:contentView attribute:cellConstraint.secondAttribute multiplier:cellConstraint.multiplier constant:cellConstraint.constant];
            parallelConstraint.priority = cellConstraint.priority;
            [cell removeConstraint:cellConstraint];
            [contentView addConstraint:parallelConstraint];
        }
    }

    // restore auto-resizing mask to iOS 7 behavior
    contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];
}

这对iOS7也适用吗? - QED

0

这不是一个 bug,我已经一直在解决这个问题并尝试了不同的方法,现在我将提供给你们我所采用的步骤:

1)使用 contentView [sampleCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

2)您可以创建自己的 contentView,并将子视图添加到该 contentView 中,如果您使用自定义 contentView,则不要忘记将其顶部、底部、左侧和右侧固定到超级视图,否则高度将为 0,在此还可以根据您的需求进行设置。例如,不将 contentView 的底部固定到超级视图上,以便视图的高度可以变化,但固定是重要的,而固定哪个取决于您的需求。

3)根据您的需求在界面构建器中正确地设置约束条件,有些约束条件无法在界面构建器中添加,但是您可以在 viewController 的 viewDidLoad 中添加它们。

所以,我的建议是:必须在界面构建器中正确设置约束条件,才能使 systemLayoutSizeFittingSize:UILayoutFittingCompressedSize 返回正确的维度,这就是解决方案。


0

可能您的约束有误,您应该同时指定您的UIView和contentView之间的垂直顶部空间和底部空间,我以前也遇到过这个问题,那是因为我只指定了垂直顶部空间,而没有指定与contentView之间的垂直底部空间


0

我在UITableViewCells和iOS 7上遇到了同样的问题(ios8完美运行),但“Triet Luong”的解决方案对我有用:

return [sampleCell.containerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

0
这是在iOS7设备上运行xCode6和iOS 8 SDK时出现的一个bug :) 它浪费了我几乎一整天的时间。最终,在UICollectionViewCell子类中使用下面的代码才解决了问题。希望这个问题会在下一个版本中得到修复。
- (void)setBounds:(CGRect)bounds {
    [super setBounds:bounds];
    self.contentView.frame = bounds;
}

我不建议使用这个修复方法。如果你使用systemLayoutSizeFittingSize:,它将无法正确工作,因为contentView不会成为约束层次结构的一部分。你需要在contentView上设置约束或设置其autoResizingMask。 - phatmann

-1

这是iOS 8 beta版本中的一个错误。 最终在iOS 8 GB(Build 12A365)中修复了该问题。 所以现在对我来说,它可以使用我为iOS 7编写的相同代码。(请参见问题)


感谢所有参与讨论并向苹果报告错误的人。 - martn_st

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接