Автоматическое изменение размеров ячеек UICollectionView, выравнивание ячейки сверху - PullRequest
1 голос
/ 26 марта 2020

У меня есть 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 ячеек. Я должен привести его в соответствие с Top.

enter image description here

РЕДАКТИРОВАТЬ: Итак, я понял, что код 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 правильно выровнены по горизонтальному центру, за исключением того, что только одна ячейка будет выровнена по левому краю.

По-прежнему нет решения для вертикального выравнивания.

1 Ответ

0 голосов
/ 27 марта 2020

Так что я работал над этим довольно долго. Никакие ответы от переполнения стека никак не помогут. Так что я играл с пользовательским UICollectionViewFlowLayout методом layoutAttributesForElements.

Этот метод будет вызываться для каждого раздела и будет иметь layoutAttributesForElements для прямоугольника. Это даст массив UICollectionViewLayoutAttributes, который можно изменить в соответствии с необходимостью.

У меня была проблема с вычислением координаты y, которую я хотел бы изменить для своих ячеек.

Итак, сначала с oop в атрибутах layoutAttributesForElements Я получил заголовок и сохранил его высоту в переменной. Затем изменил 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
    }
}

ПРИМЕЧАНИЕ : Вам необходимо скопировать атрибуты в массиве первым для работы. В противном случае xcode выкрикивает Logging only once for UICollectionViewFlowLayout cache mismatched frame в консоли.

Если есть какое-либо новое / совершенное решение, пожалуйста, дайте мне знать.

CHEERS !!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...