【问题标题】:Unable to resize cells with custom UICollectionViewFlowLayout无法使用自定义 UICollectionViewFlowLayout 调整单元格大小
【发布时间】:2020-12-12 16:43:04
【问题描述】:

我目前正在尝试在我的集合视图的每个单元格之间实现自定义分隔线视图。我在网上找到了这个答案,它在行间距中添加了自定义视图 (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
    }
}

这个解决方案确实有效,我可以看到分隔线。但是,当用户单击其中一个单元格时,就会出现问题。我想要的行为是让单元格在单击单元格时展开以显示更多详细信息。我实现这一点的方式是跟踪选择了哪些indexPaths,如果在sizeForItemAt 中选择了它们,则返回更大的尺寸。在didSelectItemAt 中,我重新加载了集合视图。这种方法在我使用普通的UICollectionViewFlowLayout 时有效,但是当我尝试使用我的自定义流布局(上图)时,我得到了以下崩溃:

no UICollectionViewLayoutAttributes instance for -layoutAttributesForDecorationViewOfKind: separator at path <NSIndexPath: 0xf75c5b66b8a0a8ab> {length = 2, path = 0 - 6}

我尝试查找解决方案,发现这两个堆栈溢出 herehere 但我尝试的答案似乎都不起作用。

我试过了:

  1. 当我重新加载集合视图时布局无效。
  2. 实现一个缓存,当我在自定义布局中覆盖 layoutAttributesForItem 时,我会从该缓存返回。

在这一点上,任何帮助将不胜感激!

【问题讨论】:

    标签: swift uicollectionviewlayout uicollectionviewflowlayout


    【解决方案1】:

    看来我必须在我的自定义布局中覆盖两个方法:

        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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-29
      • 1970-01-01
      • 2018-01-15
      • 2018-05-29
      • 2018-08-06
      相关资源
      最近更新 更多