我一直在玩动态UICollectionViewCell,并注意到在iOS 8上调用cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
上的UICollectionViewCell
会返回不正确的宽度。目前解决此问题的唯一解决方法是显式添加宽度约束以强制单元格的宽度。以下代码用于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不是为只有一个动态维度的单元格设计的,但仍然无法解释为什么单元格给出了不寻常的宽度。
我遇到了同样的问题。关键是在获取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;
}
我的存储库中提供了SSCCE(示例):
https://github.com/knutvalen/sandbox-uicollectionview
下面是主要代码的片段。
斯威夫特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
}
产量
在我的情况下,它没有正确计算宽度,因为我在调用systemLayoutSizeFittingSize
方法之前缺少这两行:
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];
花了好几个小时才发现它,所以希望它对其他有类似问题的人有所帮助。