在 iOS 8 中 UICollectionViewFlowLayout
支持根据自己的内容大小自动调整单元格的大小。这会根据内容调整单元格的宽度和高度。
是否可以为所有单元格的宽度(或高度)指定一个固定值并允许其他尺寸调整大小?
举一个简单的例子,考虑一个单元格中的多行标签,其约束将其定位到单元格的两侧。多行标签可以以不同的方式调整大小以适应文本。单元格应该填充集合 View 的宽度并相应地调整它的高度。相反,单元格的大小是随意的,当单元格大小大于集合 View 的不可滚动尺寸时,它甚至会导致崩溃。
iOS 8 引入方法 systemLayoutSizeFittingSize: withHorizontalFittingPriority: verticalFittingPriority:
对于集合 View 中的每个单元格,布局在单元格上调用此方法,传入估计的大小。对我来说有意义的是在单元格上覆盖此方法,传入给定的大小并将水平约束设置为 required 并将低优先级设置为垂直约束。这样水平尺寸固定为布局中设置的值,垂直尺寸可以灵活。
像这样的东西:
- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
UICollectionViewLayoutAttributes *attributes = [super preferredLayoutAttributesFittingAttributes:layoutAttributes];
attributes.size = [self systemLayoutSizeFittingSize:layoutAttributes.size withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
return attributes;
}
UILayoutFittingCompressedSize
UILayoutFittingExpandedSize
它只代表零尺寸和相当大的尺寸。size
这个方法的参数真的只是传入两个常量的一种方式吗?有没有办法实现我期望为给定尺寸获得适当高度的行为?最佳答案
听起来您要求的是一种使用 UICollectionView 生成 UITableView 之类的布局的方法。如果这确实是您想要的,那么正确的方法是使用自定义 UICollectionViewLayout 子类(可能类似于 SBTableLayout )。
另一方面,如果你真的问是否有一种干净的方法可以使用默认的 UICollectionViewFlowLayout 来做到这一点,那么我相信没有办法。即使使用 iOS8 的自定大小单元格,也不是那么简单。正如您所说,基本问题是流布局的机制无法修复一个维度并让另一个维度做出响应。 (此外,即使可以,需要两次布局传递来调整多行标签的大小也会带来额外的复杂性。这可能不符合自调整大小单元格希望通过一次调用 systemLayoutSizeFittingSize 来计算所有大小的方式。)
然而,如果你仍然想创建一个类似 tableview 的布局,使用流布局,单元格决定自己的大小,并自然地响应集合 View 的宽度,当然这是可能的。还是有乱七八糟的方式。我已经使用“调整单元格大小”完成了它,即 Controller 保留仅用于计算单元格大小的非显示 UICollectionViewCell。
这种方法有两个部分。第一部分是让集合 View 委托(delegate)计算正确的单元格大小,通过获取集合 View 的宽度并使用大小调整单元格来计算单元格的高度。
在您的 UICollectionViewDelegateFlowLayout 中,您实现了这样的方法:
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
// NOTE: here is where we say we want cells to use the width of the collection view
let requiredWidth = collectionView.bounds.size.width
// NOTE: here is where we ask our sizing cell to compute what height it needs
let targetSize = CGSize(width: requiredWidth, height: 0)
/// NOTE: populate the sizing cell's contents so it can compute accurately
self.sizingCell.label.text = items[indexPath.row]
let adequateSize = self.sizingCell.preferredLayoutSizeFittingSize(targetSize)
return adequateSize
}
preferredLayoutSizeFittingSize
中完成,就像这样: /*
Computes the size the cell will need to be to fit within targetSize.
targetSize should be used to pass in a width.
the returned size will have the same width, and the height which is
calculated by Auto Layout so that the contents of the cell (i.e., text in the label)
can fit within that width.
*/
func preferredLayoutSizeFittingSize(targetSize:CGSize) -> CGSize {
// save original frame and preferredMaxLayoutWidth
let originalFrame = self.frame
let originalPreferredMaxLayoutWidth = self.label.preferredMaxLayoutWidth
// assert: targetSize.width has the required width of the cell
// step1: set the cell.frame to use that width
var frame = self.frame
frame.size = targetSize
self.frame = frame
// step2: layout the cell
self.setNeedsLayout()
self.layoutIfNeeded()
self.label.preferredMaxLayoutWidth = self.label.bounds.size.width
// assert: the label's bounds and preferredMaxLayoutWidth are set to the width required by the cell's width
// step3: compute how tall the cell needs to be
// this causes the cell to compute the height it needs, which it does by asking the
// label what height it needs to wrap within its current bounds (which we just set).
let computedSize = self.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
// assert: computedSize has the needed height for the cell
// Apple: "Only consider the height for cells, because the contentView isn't anchored correctly sometimes."
let newSize = CGSize(width:targetSize.width,height:computedSize.height)
// restore old frame and preferredMaxLayoutWidth
self.frame = originalFrame
self.label.preferredMaxLayoutWidth = originalPreferredMaxLayoutWidth
return newSize
}
preferredMaxLayoutWidth
以便标签将在自动布局中使用该宽度。只有这样你才能使用systemLayoutSizeFittingSize
为了让单元格在考虑标签的同时计算其高度。preferredLayoutAttributesFittingAttributes:
我认为,方法是一个红鲱鱼。那只能与新的自定大小单元机制一起使用。因此,只要该机制不可靠,这就不是答案。systemLayoutSizeFittingSize:
上的文档和 systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
两者都建议你应该只通过 UILayoutFittingCompressedSize
和 UILayoutFittingExpandedSize
如 targetSize
.但是,方法签名本身、标题注释和函数的行为表明它们正在响应 targetSize
的确切值。参数。UICollectionViewFlowLayoutDelegate.estimatedItemSize
,为了启用新的自调整单元格机制,该值似乎作为 targetSize 传入。和 UILabel.systemLayoutSizeFittingSize
似乎返回与 UILabel.sizeThatFits
完全相同的值.鉴于 systemLayoutSizeFittingSize
的论点,这是可疑的。应该是一个粗略的目标和参数 sizeThatFits:
应该是最大外接尺寸。https://stackoverflow.com/questions/26143591/