Как изменить форму элемента определенной группы при использовании uicollectionviewкомпозиционно

#swift #xcode #uicollectionview #uibezierpath #uicollectionviewcompositionallayout

Вопрос:

Я создаю приложение для коллажей, для которого я буду использовать несколько макетов сетки.Я использую UICollectionViewCompositionalLayout для создания сеток. Для одной из моих сеток требуется ячейка в форме сердца между ними. Ниже приведен мой код, элемент в форме сердца должен быть в форме сердца, я понятия не имею, как это сделать, сначала я подумал об использовании UIBeizerPath, но элемент не относится к типу слоя, и если мне каким-то образом удастся сделать это внутри cellForItem, все равно у меня будет еще много сеток, и мне придется снова и снова использовать «если», «иначе». Еще одна проблема, с которой я столкнулся в своей последней группе, т. е. нижняя группа не отображается.

Любая помощь была бы очень признательна.

                 let topItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalHeight(1)))
                
//                top items group
                let topGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/4)), subitem: topItem, count: 3)
                topGroup.contentInsets = .init(top: 0, leading: 3, bottom: 0, trailing: 3)
                topGroup.interItemSpacing = .fixed(2)

//                middle right item
                let middleRightItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/4), heightDimension: .fractionalHeight(1)))

//                 middle left item
                let middleLeftItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/4), heightDimension: .fractionalHeight(1)))

//                Heart Shaped
                let heartShapedItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/2), heightDimension: .fractionalHeight(1)))

//                 middle three items group
                let middleGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/3)), subitems: [middleRightItem,heartShapedItem,middleLeftItem])
                middleGroup.contentInsets = .init(top: 0, leading: 3, bottom: 0, trailing: 3)
                middleGroup.interItemSpacing = .fixed(2)

//            bottom three items group
                let bottomGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/4)), subitem: topItem, count: 3)
                
                let finalGroup = NSCollectionLayoutGroup.vertical(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1)), subitems: [topGroup,middleGroup,bottomGroup])
                finalGroup.interItemSpacing = .fixed(2)
                
                let section = NSCollectionLayoutSection(group: finalGroup)
                
                return section
 

Ответ №1:

Макет представления коллекции определяет визуальное расположение содержимого в вашей коллекции — таким образом, UICollectionViewCompositionalLayout вы указываете в своем представлении коллекции такие параметры, как количество элементов в строке, размеры и смещения, поведение ортогональной прокрутки, заголовки и элементы оформления, а не то, как выглядит определенная ячейка.

В cellForItem вы можете настроить свои ячейки, включая их слои, — вы можете изменять формы там. Ячейки будут расположены в представлении коллекции на основе ваших параметров UICollectionViewCompositionalLayout .

Если вы используете UICollectionViewDiffableDataSource , вы можете различать различные типы ячеек (т. Е. Ячейки в форме сердца и круга) с помощью следующего примера кода:

 func configureDataSource() {
    dataSource = DataSource(collectionView: collectionView) { [self] (collectionView: UICollectionView, indexPath: IndexPath, item: ViewCell) -> UICollectionViewCell? in
        switch item.type {
        case .heart:  return hearCell(for: indexPath)
        case .circle: return circleCell(for: indexPath)
        default:      return normalCell(for: indexPath)
        }
    }
}
 

В пользовательской ячейке просмотра структуры у меня есть перечисление для типа ячейки:

 struct ViewCell: Hashable {
    var tag: Int
    var type: CellType
}

enum CellType { case heart, circle }
 

Что касается проблемы с нижней группой — достаточно ли у вас элементов в представлении коллекции, чтобы заполнить все группы?

Обновить:

Проблема в вашем макете связана с этой строкой:

 middleGroup.interItemSpacing = .fixed(2)
 

При этом 3 ряда в средней группе не могут быть помещены в один ряд. Вы можете удалить его и добиться такого же расстояния, добавив вставки в средний элемент:

 heartShapedItem.contentInsets = .init(top: 0, leading: 2, bottom: 0, trailing: 2)
 

Поскольку вы не используете UICollectionViewDiffableDataSource , вы можете дифференцировать свои клетки по indexPath. Таким образом, если у вас есть только 1 раздел, ваш элемент HEARTshape будет иметь indexPath.строка из 4:

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCollectionViewCell.reuseID, for: indexPath) as? MyCollectionViewCell else { return UICollectionViewCell() }

    cell.label.text = "(indexPath.row)"
    cell.label.textAlignment = .center
    cell.backgroundColor = .green
    
    if indexPath == IndexPath(row: 4, section: 0) {
        cell.label.text = "HEART"
    }
    
    return cell
}
 

введите описание изображения здесь

(в вашем исходном коде нет интервала между элементами в нижней группе, я не знаю, было ли это сделано намеренно или нет)

Комментарии:

1. да, у меня достаточно всего, что я использую topitem дважды

2. можете ли вы сказать мне, как я могу использовать перечисление с помощью UICollectionViewКомпозиционноЕотказ извините, я еще не очень хорошо разбираюсь в swift, если хотите, я могу поделиться своим кодом для flowlayout

3. UICollectionViewCompositionalLayout может использоваться либо с UICollectionViewDataSource (который вы используете), либо с UICollectionViewDiffableDataSource (который я предлагаю использовать). Перечисление, которое я показал в своем ответе, является частью UICollectionViewDiffableDataSource и позволяет дифференцировать ячейки не только по indexPath (как в вашем случае с CollectionView(_:cellForItemAt:)), но и с помощью пользовательского элемента. Пользовательский элемент может иметь столько свойств, сколько вам нужно, включая перечисление для типа ячейки.

4. Источник данных = UICollectionViewDiffableDataSource<Раздел,модель изображения>(Представление коллекции: Представление коллекции!) { [self] (CollectionView, indexPath, изображение) -> CollectionViewCell Это мой источник diffabledatasource Я действительно запутался в том, как использовать перечисление извините за беспокойство, но у меня мало опыта работы со swift. Мне понравилось, как работает diffable, теперь я изменил свой код на diffable, но все еще не уверен, как получить доступ к элементу с помощью перечисления.

5. Большое вам спасибо, Виктор, это было не совсем то, что я хотел сделать, но вы очень приблизили меня к тому, что я хотел сделать, и я сделал это с вашей помощью