User95797654974
User95797654974

Reputation: 624

How to correctly indent the last row bottom separator of UICollectionViewCompositionalLayout?

I am able to hide the bottom separator of the last row but unable to correctly indent based on my SwiftUI view in my collection view cell. How do I correctly indent it like the rest of my cells instead of being edge to edge?

I am aware you can set the indents manually in the list configuration but is there a better automatic way?

class ViewController: UIViewController {
    var collectionView: UICollectionView!
    var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
    private var headerRegistration: UICollectionView.SupplementaryRegistration<UICollectionViewCell>!

    var items: [Item] = [
        Item(title: "Item 1"),
        Item(title: "Item 2"),
        Item(title: "Item 3"),
        Item(title: "Item 4"),
        Item(title: "Item 5")
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
                
        registerHeader()
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(collectionView)
        
        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            collectionView.bottomAnchor.constraint(equalTo: addButton.topAnchor)
        ])
        
        collectionView.register(UICollectionViewListCell.self, forCellWithReuseIdentifier: "cell")
        
        configureDataSource()
        applySnapshot()
    }
    
    func registerHeader() {
        headerRegistration = .init(elementKind: UICollectionView.elementKindSectionHeader) {
            (header, elementKind, indexPath) in

            header.contentConfiguration = UIHostingConfiguration {
                Button {
                    
                } label: {
                    Text("Header")
                        .frame(width: 100, height: 50)
                        .contentShape(.rect)
                        .buttonStyle(.bordered)
                }
            }
        }
    }

    func createLayout() -> UICollectionViewLayout {
        var listConfiguration = UICollectionLayoutListConfiguration(appearance: .grouped)
        listConfiguration.headerMode = .supplementary

        listConfiguration.itemSeparatorHandler = { [unowned self] (indexPath, sectionSeparatorConfiguration) in
            var configuration = sectionSeparatorConfiguration
            if indexPath.row == 0 {
                configuration.topSeparatorVisibility = .hidden
            } else if indexPath.row == items.count - 1 {
                //Correctly the last row separator here?
                configuration.bottomSeparatorVisibility = .hidden
            }
            
            return configuration
        }

        let layout = UICollectionViewCompositionalLayout.list(using: listConfiguration)
        return layout
    }

    func configureDataSource() {
        dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { (collectionView, indexPath, item) -> UICollectionViewCell? in
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! UICollectionViewListCell
            cell.contentConfiguration = UIHostingConfiguration {
                HStack {
                    Image(systemName: "house")
                        .resizable()
                        .foregroundStyle(.gray)
                        .scaledToFit()
                        .padding()
                        .frame(width: 50, height: 50)
                        .background(.quaternary)
                        .cornerRadius(5)
                        .padding(.trailing, 5)

                    VStack(alignment: .leading) {
                        Text("Item name")
                            .lineLimit(1)
                        Text("Item subtitle")
                            .font(.subheadline)
                            .foregroundColor(.secondary)
                            .lineLimit(1)
                    }
                }
            }
            .margins(.all, 5)
            
            return cell
        }
                
        dataSource.supplementaryViewProvider = { [unowned self] collectionView, elementKind, indexPath in
            return collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: indexPath)
        }
    }

    func applySnapshot(animatingDifferences: Bool = true) {
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.main])
        snapshot.appendItems(items)
        dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
    }
}

Upvotes: 0

Views: 30

Answers (0)

Related Questions