我目前正在尝试在集合视图的每个单元格之间实现自定义分隔符视图。我在网上找到了这个答案,并在行间距(link)中添加了自定义视图。
private let separatorDecorationView = "separator"
final class CustomFlowLayout: UICollectionViewFlowLayout {
override init() {
super.init()
register(SeparatorView.self,
forDecorationViewOfKind: separatorDecorationView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let layoutAttributes = super.layoutAttributesForElements(in: rect) ?? []
let lineWidth = self.minimumLineSpacing
var decorationAttributes: [UICollectionViewLayoutAttributes] = []
// skip first cell
for layoutAttribute in layoutAttributes where layoutAttribute.indexPath.item > 0 {
let separatorAttribute = UICollectionViewLayoutAttributes(forDecorationViewOfKind: separatorDecorationView,
with: layoutAttribute.indexPath)
let cellFrame = layoutAttribute.frame
separatorAttribute.frame = CGRect(x: cellFrame.origin.x,
y: cellFrame.origin.y - lineWidth,
width: cellFrame.size.width,
height: lineWidth)
separatorAttribute.zIndex = Int.max
decorationAttributes.append(separatorAttribute)
}
return layoutAttributes + decorationAttributes
}
}
private final class SeparatorView: UICollectionReusableView {
private let imageView: UIImageView = {
let iv = UIImageView(image: UIImage(named: "cell-divider"))
iv.contentMode = .scaleAspectFit
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(imageView)
imageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
imageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
self.frame = layoutAttributes.frame
}
}
此解决方案实际上有效,并且我能够看到分隔线。但是,当用户单击单元格之一时,就会出现问题。我想要的行为是单击该单元格时,该单元格可以展开以显示更多详细信息。我实现此方法的方式是跟踪所选的indexPath
,如果在sizeForItemAt
中选择了它们,则返回更大的大小。在didSelectItemAt
中,我重新加载了集合视图。当我使用普通的UICollectionViewFlowLayout
时,这种方法有效,但是当我尝试使用自定义流布局(如上)时,出现以下崩溃:
no UICollectionViewLayoutAttributes instance for -layoutAttributesForDecorationViewOfKind: separator at path <NSIndexPath: 0xf75c5b66b8a0a8ab> {length = 2, path = 0 - 6}
我尝试查找解决方案,发现这两个堆栈溢出here和here,但是我尝试的所有答案似乎都不起作用。
我尝试过:
layoutAttributesForItem
时返回的缓存。在此刻,任何帮助将不胜感激!
答案 0 :(得分:0)
似乎我必须在自定义布局中覆盖两个方法:
override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let layoutAttributes = UICollectionViewLayoutAttributes(forDecorationViewOfKind: elementKind,
with: indexPath)
return layoutAttributes;
}
override func initialLayoutAttributesForAppearingDecorationElement(ofKind elementKind: String, at decorationIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = layoutAttributesForDecorationView(ofKind: elementKind,
at: decorationIndexPath)
return attributes
}
重新加载数据时,我还需要保留布局无效调用。
collectionView.reloadData()
let context = collectionViewLayout.invalidationContext(forBoundsChange: bounds)
context.contentOffsetAdjustment = CGPoint.zero
collectionView.collectionViewLayout.invalidateLayout(with: context)
layoutSubviews()