Search code examples
iosswiftuicollectionviewuikituicollectionviewlayout

UICollectionView: remove separators for specific cells only


I need to show separators for every cell in UICollectionView except every first cell of a section. I'm using list layout. So far I have only been able to remove all separators using configuration.showsSeparators = false.

My UICollectionView configuration:

let collectionView: UICollectionView = {
    let provider = { (_: Int, layoutEnv: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
        var configuration = UICollectionLayoutListConfiguration(appearance: .grouped)
        configuration.showsSeparators = true // <----- shows separators for every cell
        configuration.footerMode = .supplementary
        return .list(using: configuration, layoutEnvironment: layoutEnv)
    }
    let listLayout = UICollectionViewCompositionalLayout(sectionProvider: provider)
    return UICollectionView(frame: .zero, collectionViewLayout: listLayout)
}()

Cell registartion:

let cellRegistration = UICollectionView.CellRegistration<MailboxCell, MailAccount> {
    (cell, indexPath, listItem) in
    // some setup code
}

dataSource = UICollectionViewDiffableDataSource<Account, ListItem>(collectionView: collectionView) { 
    (collectionView, indexPath, listItem) -> UICollectionViewCell? in

    // some setup
    return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: listItem)
}


Solution

  • UICollectionLayoutListConfiguration has a handler closure which allows you to configure the separator appearance on an item-by-item basis: itemSeparatorHandler (https://developer.apple.com/documentation/uikit/uicollectionlayoutlistconfiguration/3727737-itemseparatorhandler).

    If you don't want bottom separators for the first item in each section you can add a handler to your UICollectionLayoutListConfiguration that hides the separator for the first item:

    let collectionView: UICollectionView = {
        let provider = { (_: Int, layoutEnv: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
            var configuration = UICollectionLayoutListConfiguration(appearance: .grouped)
            configuration.footerMode = .supplementary
    
            // Hide bottom separator for first item in each section
            configuration.itemSeparatorHandler = { indexPath, sectionSeparatorConfiguration in
                var configuration = sectionSeparatorConfiguration
                configuration.bottomSeparatorVisibility = indexPath.row == 0 ? .hidden : .visible
                return configuration
            }
    
            return .list(using: configuration, layoutEnvironment: layoutEnv)
        }
        let listLayout = UICollectionViewCompositionalLayout(sectionProvider: provider)
        return UICollectionView(frame: .zero, collectionViewLayout: listLayout)
    }()
    

    It looks like showsSeparators defaults to true for the grouped appearance so you don't need to explicitly set that.

    If you also want to remove the top separator you can easily do that too by adjusting topSeparatorVisibility in the handler in the same way.