Ios 自动调整UICollectionView单元格的大小,将单元格与顶部对齐

Ios 自动调整UICollectionView单元格的大小,将单元格与顶部对齐,ios,swift,uicollectionview,flowlayout,uicollectionviewflowlayout,Ios,Swift,Uicollectionview,Flowlayout,Uicollectionviewflowlayout,我有一个UICollectionView,有多个部分和行。 页眉和页脚视图(如有必要),大小固定。 可自动调整大小的单元格 单元视图的设计如下所示: 绿色-图像视图 橙色-标签带有numberOfLines=0 单元格应根据标签numberOfLines扩展其大小 我在MyCustomCell中使用以下代码实现了这一点: override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayou

我有一个UICollectionView,有多个部分和行。 页眉和页脚视图(如有必要),大小固定。 可自动调整大小的单元格

单元视图的设计如下所示:

绿色-图像视图

橙色-标签带有
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(青色)在垂直和水平方向上都居中对齐

我需要使其与顶部垂直对齐。

我的页眉和页脚也有对齐问题。为此,我将
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
    }

}

这是一张说明当前情况的图片。青色是单元格的内容视图。我必须使它与顶部对齐

编辑: 所以我意识到,
UICollectionViewFlowLayout
code产生的bug比修复问题多。我添加了
layouttributesforements
,以便在只有一个单元格的情况下将单元格左对齐。它实际上是把我所有的细胞向左对齐。 将代码修改为


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

此方法将调用每个节,并且将为rect使用
layouttributesforements
。这将提供一个
UICollectionViewLayoutAttribute的数组,用户可以根据需要修改这些属性

我在计算要为单元格更改的
y
坐标时遇到问题

因此,首先通过
layouttributesforements
中的属性循环,我得到了标题,并将其高度保存在一个变量中。然后将单元格的其余部分的
y
坐标更改为headerHeight值

不确定这是否正确,也没有进行任何性能测试。现在一切似乎都很好,没有任何滞后或急促

以下是完整代码或自定义
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
    }
}

注意:首先需要复制数组中的属性才能使用。对于控制台中的UICollectionViewFlowLayout缓存不匹配的帧,否则xcode只会大叫一次
日志记录

如果有任何新的/完美的解决方案,请告诉我


干杯

所以我在这方面做了很多工作。没有来自堆栈溢出帮助的任何答案。因此,我使用了自定义
UICollectionViewFlowLayout
方法
layoutAttributesForElements

此方法将调用每个节,并且将为rect使用
layouttributesforements
。这将提供一个
UICollectionViewLayoutAttribute的数组,用户可以根据需要修改这些属性

我在计算要为单元格更改的
y
坐标时遇到问题

因此,首先通过
layouttributesforements
中的属性循环,我得到了标题,并将其高度保存在一个变量中。然后将单元格的其余部分的
y
坐标更改为headerHeight值

不确定这是否正确,也没有进行任何性能测试。现在一切似乎都很好,没有任何滞后或急促

以下是完整代码或自定义
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
    }
}

注意:首先需要复制数组中的属性才能使用。对于控制台中的UICollectionViewFlowLayout缓存不匹配的帧,否则xcode只会大叫一次
日志记录

如果有任何新的/完美的解决方案,请告诉我

干杯