I have the following problem:
I want to add horizontal insets to a collectionView's contentView, but when I set the contentInset
to UIEdgeInsets(top: .zero, left: 64, bottom: .zero, right: 64)
for example, it scrolls the contentView rather than reducing its width.
I'm using a UICollectionViewCompositionalLayout
of type .list
.
I can set the edge insets when using a UICollectionViewCompositionalLayout
that uses a custom NSCollectionLayoutSection
(I apply the inset to the section's group), but when using Apple's default list designs I don't seem to be able to.
How can I use Apple's default designs for the various states in lists (editing, reordering) and add edge insets in order to reduce the contentView's width?
Here the viewController
I'm working with:
import SwiftUI
import UIKit
final class AppearancePlainViewController: UIViewController {
struct Contact: Identifiable, Hashable {
let id: UUID = UUID()
let name: String = "Arthur"
let surname: String = "Dent"
let image: UIImage = UIImage(systemName: "person")!
}
private enum ListSection: Int {
case main
}
private enum ListRow: Hashable {
enum ListContentConfiguration: Hashable {
case cell
}
case example(ListContentConfiguration, Contact)
case description(String)
}
private typealias Section = ListSection
private typealias Row = ListRow
private typealias DataSource = UICollectionViewDiffableDataSource<Section, Row>
private typealias Snapshot = NSDiffableDataSourceSnapshot<Section, Row>
private let rows: [ListRow] = [
.example(.cell, Contact()),
.description(".cell"),
.example(.cell, Contact()),
.description(".cell1"),
.example(.cell, Contact()),
.description(".cell2"),
.example(.cell, Contact()),
.description(".cell3"),
.example(.cell, Contact()),
.description(".cell4"),
.example(.cell, Contact()),
.description(".cell5"),
.example(.cell, Contact()),
.description(".cell6"),
.example(.cell, Contact()),
.description(".cell7"),
.example(.cell, Contact()),
.description(".cell8"),
]
private weak var collectionView: UICollectionView!
private var datasource: DataSource!
override func viewDidLoad() {
super.viewDidLoad()
title = "Appearance.plain"
view.backgroundColor = .orange
configureViewHierarchy()
configureDataSource()
loadData()
collectionView.isEditing = true
}
private func configureViewHierarchy() {
let layout = createLayout()
let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.delegate = self
collectionView.contentInset = UIEdgeInsets(top: .zero, left: 64, bottom: .zero, right: 64)
view.addSubview(collectionView)
self.collectionView = collectionView
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
])
}
private func createLayout() -> UICollectionViewLayout {
var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
let layout = UICollectionViewCompositionalLayout.list(using: configuration)
return layout
}
private func configureDataSource() {
let descriptionRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, _, item in
cell.contentConfiguration = UIHostingConfiguration {
ZStack {
Text(item)
.font(.caption2)
.padding(.horizontal, 2.0)
}
.foregroundColor(Color(UIColor.systemBackground))
.background(Color(UIColor.label))
.cornerRadius(2.0)
.padding(.bottom, 2.0)
}
var backgroundConfig = UIBackgroundConfiguration.listPlainCell()
backgroundConfig.backgroundColor = .blue
cell.backgroundConfiguration = backgroundConfig
}
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Contact> { cell, _, item in
var configuration = UIListContentConfiguration.cell()
configuration.text = item.name
configuration.secondaryText = item.surname
configuration.image = item.image
cell.contentConfiguration = configuration
cell.backgroundConfiguration = .listPlainCell()
}
datasource = DataSource(collectionView: collectionView) { collectionView, indexPath, identifier -> UICollectionViewCell in
switch identifier {
case .example(let configType, let contact):
switch configType {
case .cell:
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: contact)
}
case .description(let string):
return collectionView.dequeueConfiguredReusableCell(using: descriptionRegistration, for: indexPath, item: string)
}
}
}
private func loadData() {
var snapshot = Snapshot()
snapshot.appendSections([.main])
snapshot.appendItems(rows, toSection: .main)
datasource.applySnapshotUsingReloadData(snapshot)
}
}
extension AppearancePlainViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, canEditItemAt indexPath: IndexPath) -> Bool {
return true
}
func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt currentIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
return proposedIndexPath
}
}
I don't think the compositional layout API cares about
UICollectionView.contentInsets
at all.You can create a
NSCollectionLayoutSection
with your own customcontentInsets
: