使用UICollectionViewCompositionalLayout.list时如何为contentView添加内边距
为UICollectionView列表样式添加水平内边距且保留默认编辑状态
问题背景
想要为UICollectionView的contentView添加水平内边距,但设置collectionView.contentInset = UIEdgeInsets(top: .zero, left: 64, bottom: .zero, right: 64)时,内容会可横向滚动而非单元格宽度自动缩小。当前使用UICollectionViewCompositionalLayout.list创建默认列表样式,自定义NSCollectionLayoutSection时可给group加内边距,但希望保留Apple默认列表的编辑、重排等交互状态。
解决方案:通过sectionProvider自定义列表section内边距
使用UICollectionLayoutListConfiguration的sectionProvider回调,获取系统默认生成的section布局,修改其group的水平内边距即可。这种方式既能保留默认列表的所有交互逻辑,又能实现内容宽度缩小的效果,不会触发横向滚动。
关键修改步骤
- 移除
collectionView.contentInset的设置,避免内容可横向滚动 - 在创建
UICollectionLayoutListConfiguration时,设置sectionProvider回调,调整section的group内边距
修改后的完整代码
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 // 移除contentInset设置,避免横向滚动 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) // 设置sectionProvider自定义section内边距 configuration.sectionProvider = { sectionIndex, layoutEnvironment in // 获取系统默认的列表section var section = UICollectionLayoutListConfiguration.listSection( for: sectionIndex, layoutEnvironment: layoutEnvironment, configuration: configuration ) // 给section的group添加水平内边距 section.contentInsets = UIEdgeInsets(top: .zero, left: 64, bottom: .zero, right: 64) return section } 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 } }
效果说明
- 单元格内容会自动适配内边距,宽度缩小,不会出现横向滚动
- 列表的编辑、重排等默认交互状态完全保留,没有任何破坏
内容的提问来源于stack exchange,提问作者schmittsfn
相关产品推荐
相关产品推荐

