【问题标题】:UICollectionViewCell systemLayoutSizeFittingSize returns incorrect widthUICollectionViewCell systemLayoutSizeFittingSize 返回不正确的宽度
【发布时间】:2015-04-24 14:37:38
【问题描述】:

我一直在玩弄动态 UICollectionViewCell,并注意到在 iOS 8 上,在 UICollectionViewCell 上调用 cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 返回的宽度不正确。目前,解决此问题的唯一解决方法是显式添加宽度约束以强制单元格的宽度。以下代码用于 Cell 子类:

func calculatePreferredHeightForFrame(frame: CGRect) -> CGFloat {
    var newFrame = frame
    self.frame = newFrame
    let widthConstraint = NSLayoutConstraint(item: contentView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: CGRectGetWidth(frame))
    contentView.addConstraint(widthConstraint)
    self.setNeedsUpdateConstraints()
    self.updateConstraintsIfNeeded()
    self.setNeedsLayout()
    self.layoutIfNeeded()
    let desiredHeight: CGFloat = self.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    newFrame.size.height = CGFloat(ceilf(Float(desiredHeight)))
    contentView.removeConstraint(widthConstraint)
    return CGRectGetHeight(newFrame)
}

我知道在 iOS 8 和动态 UICollectionViewFlowLayout 中,UICollectionViewCell 的 contentView 以不同方式处理约束,但是我在这里缺少什么吗?需要做什么来确保 systemLayoutSizeFittingSize 在单元格上使用特定宽度?

我也看到了这篇文章 (Specifying one Dimension of Cells in UICollectionView using Auto Layout),并相信这实际上可能会使我的问题无效。也许 UICollectionViewFlowLayout 不是为只有一个动态维度的单元格设计的,但这仍然不能解释为什么单元格会给出不寻常的宽度。

【问题讨论】:

  • 我有完全相同的问题,我的单元格宽度总是返回为 320(xib 视图大小)。无法真正解决它...
  • 这个单元格中有多行 UILabel 吗?如果是这样,您可能有错误的首选最大布局宽度。
  • @hris.to 如果您再次阅读该问题,您会发现它与标签无关,而是与整个单元格的大小有关
  • @DanielGalasko 确定我明白这一点。几天前 UITableViewCell 就发生在我身上。如果将preferedMaxLayoutWidth 设置为240px,它将像一个约束一样,当收到systemLayoutSizeFittingSize 时,它​​会返回比实际帧宽度更大的宽度。您必须继承标签并覆盖 setBounds 以根据新标签宽度更新 preferredMaxLayoutWidth(仅在值不同时更新它,并且在 super setBounds 调用之后)。
  • 如果您在实施此解决方案时遇到问题,请告诉我,所以我会留下完整解决方案的答案。

标签: ios xcode6 autolayout uicollectionview


【解决方案1】:

我也遇到过同样的问题。关键是在获取systemLayoutSize时使用优先级。

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (!self.prototypeCell) {
        self.prototypeCell = [TrainingMenuCell new];
        self.prototypeCell.contentView.translatesAutoresizingMaskIntoConstraints = NO;
    }

    [self configureCell:self.prototypeCell forIndexPath:indexPath];
    [self.prototypeCell setNeedsLayout];
    [self.prototypeCell layoutIfNeeded];

    CGFloat width = CGRectGetWidth(collectionView.frame) - 12;
    CGSize fittingSize = UILayoutFittingCompressedSize;
    fittingSize.width = width;

    CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:fittingSize withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityDefaultLow];
    return size;
}

【讨论】:

  • 减法部分不适合我。我从 collectionview 宽度中减去 20,因为我在左右两边都有 10 的部分插图。但我仍然以 320 而不是 300 结束。
  • @Nil 你检查过fittingSizesize 变量吗?优先级是从我的回答中复制的吗?
  • 没关系。实际上我使用的是 self.prototypeCell 而不是 self.prototypeCell.contentView。这就是它坏掉的原因。
  • 既然我们谈论的是同一个主题,您知道如何将水平集合视图的高度设置为列表中最大高度单元格的高度吗?
  • @Nil 你应该自己做。每次重新加载 CV 时,分别计算尺寸以确定最大高度。或者也许自定义 CVL 可以帮助您。
【解决方案2】:

我的存储库中提供了一个 SSCCE(示例):

https://github.com/knutvalen/sandbox-uicollectionview

下面是主要代码的sn-p。

斯威夫特 4

var array = ["foo", "bar", "baz"]

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)

    if let myCell = cell as? MyCollectionViewCell {
        myCell.titleLabel.text = array[indexPath.item]
        myCell.subtitleLabel.text = "my subtitle for " + array[indexPath.item] + " is a very long text with many letters and words"
        return myCell
    }

    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let forcedWidth: CGFloat = 200
    let myCell = MyCollectionViewCell()
    myCell.titleLabel.text = array[indexPath.item]
    myCell.subtitleLabel.text = "my subtitle for " + array[indexPath.item] + " is a very long text with many letters and words"
    myCell.subtitleLabel.preferredMaxLayoutWidth = forcedWidth - (myCell.myMargin * 2)
    let optimalSize = myCell.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
    let forcedSize = CGSize(width: forcedWidth, height: optimalSize.height)
    return forcedSize
}

输出

【讨论】:

  • 这实际上并没有回答我的问题。我正在尝试明确强制单元格的宽度。即尝试使用集合视图创建 UITableView。如果您尝试上面的代码,您会发现它不起作用:)
  • @DanielGalasko 当然,你是对的。我没有正确理解您的问题。现在我更新了答案以对所有单元格强制设置宽度。
  • 我认为您需要在发布之前正确尝试该代码。您甚至在设置宽度之前计算单元格的大小,这意味着单元格可能是我们所知道的任何宽度。还可以尝试在横向和 iPad 等中进行测试。请参阅 stackoverflow.com/questions/26143591/… 以真正了解我的问题,但我认为快速解决方案没有意义,是吗?
  • @DanielGalasko 我用一个完整的 Xcode 项目更新了我的答案,以消除任何误解。请查看github.com/knutvalen/sandbox-uicollectionview 以获得完整的示例。
  • @mihirmehta 你如何尝试增加它?
【解决方案3】:

在我的情况下,它没有正确计算宽度,因为我在调用 systemLayoutSizeFittingSize 方法之前错过了这两行:

[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];

花了几个小时才发现它,所以希望它对其他有类似问题的人有所帮助。

【讨论】:

  • 这也解决了我为 UITableView 页脚计算适当大小的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-30
  • 2016-05-31
  • 1970-01-01
  • 2012-08-18
  • 2015-12-06
相关资源
最近更新 更多