自动调整 UICollectionView 单元格的大小,将单元格对齐到顶部
Autoresize UICollectionView cells, Align cell to top
我有一个 UICollectionView,有多个部分和行。
必要时固定大小的页眉和页脚视图。
可自动调整大小的单元格
单元格视图设计如下:
绿色 - ImageView
橙色 - 带有 numberOfLines = 0
的标签。
单元格应根据标签 numberOfLines
.
扩展其大小
我在 MyCustomCell 中使用这段代码实现了这一点:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
super.apply(layoutAttributes)
let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
let targetSize = CGSize(width: Constants.screenWidth/3.5, height: 0)
let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.defaultLow)
let autoLayoutFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: autoLayoutSize)
autoLayoutAttributes.frame = autoLayoutFrame
return autoLayoutAttributes
}
单元格正在自动调整大小,但 contentView(青色)在垂直和水平方向上居中对齐。
I need to make it vertically align to Top.
我也遇到了页眉和页脚的对齐问题。为此,我将 UICollectionViewFlowLayout
分类为子类
class MainCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func invalidationContext(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutInvalidationContext {
let context: UICollectionViewLayoutInvalidationContext = super.invalidationContext(forPreferredLayoutAttributes: preferredAttributes, withOriginalAttributes: originalAttributes)
let indexPath = preferredAttributes.indexPath
context.invalidateSupplementaryElements(ofKind: UICollectionView.elementKindSectionFooter, at: [indexPath])
context.invalidateSupplementaryElements(ofKind: UICollectionView.elementKindSectionHeader, at: [indexPath])
return context
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
var topMargin = sectionInset.top
var leftMargin = sectionInset.left
var maxY: CGFloat = -1.0
attributes?.forEach { layoutAttribute in
guard layoutAttribute.representedElementCategory == .cell else {
return
}
if layoutAttribute.frame.origin.y >= maxY {
leftMargin = sectionInset.left
topMargin = sectionInset.top
}
layoutAttribute.frame.origin.x = leftMargin
leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
maxY = max(layoutAttribute.frame.maxY , maxY)
}
return attributes
}
}
这是一张说明当前情况的图片。青色是单元格的 contentView。我必须让它与顶部对齐。
编辑:
所以我意识到 UICollectionViewFlowLayout
代码产生的错误多于修复问题。我添加了 layoutAttributesForElements
以左对齐我的单元格,以防只有一个单元格。它实际上所做的是将我所有的单元格都向左对齐。
修改代码为
class MainCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
if attributes?.count == 1 {
if let currentAttribute = attributes?.first {
currentAttribute.frame = CGRect(x: self.sectionInset.left, y: currentAttribute.frame.origin.y, width: currentAttribute.frame.size.width, height: currentAttribute.frame.size.height)
}
}
return attributes
}
}
现在我的 UICollectionViewCell
已正确对齐到水平中心,但只有一个单元格将保持对齐。
仍然没有垂直对齐的解决方案。
所以我为此做了很多工作。堆栈溢出的答案没有任何帮助。所以我玩了自定义 UICollectionViewFlowLayout
方法 layoutAttributesForElements
.
此方法将调用每个部分,并将 layoutAttributesForElements
用于 rect。这将给出一个 UICollectionViewLayoutAttributes
的数组,可以根据需要对其进行修改。
我在计算 y
坐标时遇到问题,我想为我的单元格更改它。
所以首先在 layoutAttributesForElements
的属性中循环,我得到了 header 并将它的高度保存在一个变量中。然后将其余单元格的 y
坐标更改为 header 高度值。
不确定这是否正确,也没有进行任何性能测试。现在一切似乎都很好,没有任何滞后或混蛋。
这是完整代码或自定义代码 UICollectionViewFlowLayout
。
class MainCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attr = super.layoutAttributesForElements(in: rect)
var attributes = [UICollectionViewLayoutAttributes]()
for itemAttributes in attr! {
let itemAttributesCopy = itemAttributes.copy() as! UICollectionViewLayoutAttributes
// manipulate itemAttributesCopy
attributes.append(itemAttributesCopy)
}
if attributes.count == 1 {
if let currentAttribute = attributes.first {
currentAttribute.frame = CGRect(x: self.sectionInset.left, y: currentAttribute.frame.origin.y, width: currentAttribute.frame.size.width, height: currentAttribute.frame.size.height)
}
} else {
var sectionHeight: CGFloat = 0
attributes.forEach { layoutAttribute in
guard layoutAttribute.representedElementCategory == .supplementaryView else {
return
}
if layoutAttribute.representedElementKind == UICollectionView.elementKindSectionHeader {
sectionHeight = layoutAttribute.frame.size.height
}
}
attributes.forEach { layoutAttribute in
guard layoutAttribute.representedElementCategory == .cell else {
return
}
if layoutAttribute.frame.origin.x == 0 {
sectionHeight = max(layoutAttribute.frame.minY, sectionHeight)
}
layoutAttribute.frame = CGRect(origin: CGPoint(x: layoutAttribute.frame.origin.x, y: sectionHeight), size: layoutAttribute.frame.size)
}
}
return attributes
}
}
注意:您需要先将属性复制到数组中才能使用。否则 xcode 将在控制台中大喊 Logging only once for UICollectionViewFlowLayout cache mismatched frame
。
如果有任何 new/perfect 解决方案,请告诉我。
干杯!!!
我有一个 UICollectionView,有多个部分和行。 必要时固定大小的页眉和页脚视图。 可自动调整大小的单元格
单元格视图设计如下:
绿色 - ImageView
橙色 - 带有 numberOfLines = 0
的标签。
单元格应根据标签 numberOfLines
.
我在 MyCustomCell 中使用这段代码实现了这一点:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
super.apply(layoutAttributes)
let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
let targetSize = CGSize(width: Constants.screenWidth/3.5, height: 0)
let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.defaultLow)
let autoLayoutFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: autoLayoutSize)
autoLayoutAttributes.frame = autoLayoutFrame
return autoLayoutAttributes
}
单元格正在自动调整大小,但 contentView(青色)在垂直和水平方向上居中对齐。
I need to make it vertically align to Top.
我也遇到了页眉和页脚的对齐问题。为此,我将 UICollectionViewFlowLayout
class MainCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func invalidationContext(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutInvalidationContext {
let context: UICollectionViewLayoutInvalidationContext = super.invalidationContext(forPreferredLayoutAttributes: preferredAttributes, withOriginalAttributes: originalAttributes)
let indexPath = preferredAttributes.indexPath
context.invalidateSupplementaryElements(ofKind: UICollectionView.elementKindSectionFooter, at: [indexPath])
context.invalidateSupplementaryElements(ofKind: UICollectionView.elementKindSectionHeader, at: [indexPath])
return context
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
var topMargin = sectionInset.top
var leftMargin = sectionInset.left
var maxY: CGFloat = -1.0
attributes?.forEach { layoutAttribute in
guard layoutAttribute.representedElementCategory == .cell else {
return
}
if layoutAttribute.frame.origin.y >= maxY {
leftMargin = sectionInset.left
topMargin = sectionInset.top
}
layoutAttribute.frame.origin.x = leftMargin
leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
maxY = max(layoutAttribute.frame.maxY , maxY)
}
return attributes
}
}
这是一张说明当前情况的图片。青色是单元格的 contentView。我必须让它与顶部对齐。
编辑:
所以我意识到 UICollectionViewFlowLayout
代码产生的错误多于修复问题。我添加了 layoutAttributesForElements
以左对齐我的单元格,以防只有一个单元格。它实际上所做的是将我所有的单元格都向左对齐。
修改代码为
class MainCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
if attributes?.count == 1 {
if let currentAttribute = attributes?.first {
currentAttribute.frame = CGRect(x: self.sectionInset.left, y: currentAttribute.frame.origin.y, width: currentAttribute.frame.size.width, height: currentAttribute.frame.size.height)
}
}
return attributes
}
}
现在我的 UICollectionViewCell
已正确对齐到水平中心,但只有一个单元格将保持对齐。
仍然没有垂直对齐的解决方案。
所以我为此做了很多工作。堆栈溢出的答案没有任何帮助。所以我玩了自定义 UICollectionViewFlowLayout
方法 layoutAttributesForElements
.
此方法将调用每个部分,并将 layoutAttributesForElements
用于 rect。这将给出一个 UICollectionViewLayoutAttributes
的数组,可以根据需要对其进行修改。
我在计算 y
坐标时遇到问题,我想为我的单元格更改它。
所以首先在 layoutAttributesForElements
的属性中循环,我得到了 header 并将它的高度保存在一个变量中。然后将其余单元格的 y
坐标更改为 header 高度值。
不确定这是否正确,也没有进行任何性能测试。现在一切似乎都很好,没有任何滞后或混蛋。
这是完整代码或自定义代码 UICollectionViewFlowLayout
。
class MainCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attr = super.layoutAttributesForElements(in: rect)
var attributes = [UICollectionViewLayoutAttributes]()
for itemAttributes in attr! {
let itemAttributesCopy = itemAttributes.copy() as! UICollectionViewLayoutAttributes
// manipulate itemAttributesCopy
attributes.append(itemAttributesCopy)
}
if attributes.count == 1 {
if let currentAttribute = attributes.first {
currentAttribute.frame = CGRect(x: self.sectionInset.left, y: currentAttribute.frame.origin.y, width: currentAttribute.frame.size.width, height: currentAttribute.frame.size.height)
}
} else {
var sectionHeight: CGFloat = 0
attributes.forEach { layoutAttribute in
guard layoutAttribute.representedElementCategory == .supplementaryView else {
return
}
if layoutAttribute.representedElementKind == UICollectionView.elementKindSectionHeader {
sectionHeight = layoutAttribute.frame.size.height
}
}
attributes.forEach { layoutAttribute in
guard layoutAttribute.representedElementCategory == .cell else {
return
}
if layoutAttribute.frame.origin.x == 0 {
sectionHeight = max(layoutAttribute.frame.minY, sectionHeight)
}
layoutAttribute.frame = CGRect(origin: CGPoint(x: layoutAttribute.frame.origin.x, y: sectionHeight), size: layoutAttribute.frame.size)
}
}
return attributes
}
}
注意:您需要先将属性复制到数组中才能使用。否则 xcode 将在控制台中大喊 Logging only once for UICollectionViewFlowLayout cache mismatched frame
。
如果有任何 new/perfect 解决方案,请告诉我。
干杯!!!