iOS16中设置UICollectionLayoutListConfiguration时如何隐藏表头并移除顶部内边距
SwiftUI列表移除顶部内边距后,首个无表头Section异常显示表头的解决方法
问题场景
我开发了一个包含Section和列表组件的SwiftUI视图,每个Section默认有顶部内边距,原视图代码如下:
struct NewListView: View { @State private var list = ["1", "2", "3", "4"] var body: some View { NavigationView { List { ForEach(list, id: \.self) { item in let isHeaderHidden = item != "1" if isHeaderHidden { Section(header: Text("\(item)")) { Text("Content with Header") }.onAppear { print("item\(item)") } } else { Text("Content without header") } } } .listRowInsets(EdgeInsets()) .listStyle(.plain) .navigationTitle("NavTitle") .navigationBarTitleDisplayMode(.inline) } } }
为了移除Section的顶部内边距,我通过全局配置UICollectionLayoutListConfiguration的.headerTopPadding = 0,但原本不需要表头的第一个条目(对应item"1")却显示出了空表头。配置代码如下:
init() { if #available(iOS 16, *) { var configuration = UICollectionLayoutListConfiguration(appearance: .plain) configuration.headerMode = .supplementary configuration.headerTopPadding = 0 let layout = UICollectionViewCompositionalLayout.list(using: configuration) UICollectionView.appearance(whenContainedInInstancesOf: [UIViewController.self]).collectionViewLayout = layout } }
问题原因
设置configuration.headerMode = .supplementary后,会强制所有Section生成一个补充表头视图——哪怕你没有为Section显式设置header内容。原本第一个直接用Text的条目,在这个配置下会被自动包裹进一个Section,从而显示出空的表头。
解决方法
方法一:放弃全局配置,用SwiftUI原生调整内边距(推荐)
直接移除全局的init配置代码,通过scrollContentInsets调整列表顶部内边距,同时保持原有的Section逻辑:
struct NewListView: View { @State private var list = ["1", "2", "3", "4"] var body: some View { NavigationView { List { ForEach(list, id: \.self) { item in let isHeaderHidden = item != "1" if isHeaderHidden { Section(header: Text("\(item)")) { Text("Content with Header") } .onAppear { print("item\(item)") } } else { Text("Content without header") } } } .listRowInsets(EdgeInsets()) .listStyle(.plain) // 调整顶部内边距抵消默认间距,数值可根据实际情况微调 .scrollContentInsets(.init(top: -35, leading: 0, bottom: 0, trailing: 0)) .navigationTitle("NavTitle") .navigationBarTitleDisplayMode(.inline) } } }
方法二:修改全局配置的headerMode,统一用Section包裹条目
如果必须使用UICollectionLayoutListConfiguration,可以把headerMode改成.firstItemInSection(只有显式设置header的Section才会显示表头),同时把第一个条目也放进Section,用空视图作为header:
struct NewListView: View { @State private var list = ["1", "2", "3", "4"] var body: some View { NavigationView { List { ForEach(list, id: \.self) { item in if item == "1" { // 用空视图作为header,隐藏表头 Section(header: EmptyView().frame(height: 0)) { Text("Content without header") } // 隐藏顶部分隔线(可选) .listSectionSeparator(.hidden, edges: .top) } else { Section(header: Text("\(item)")) { Text("Content with Header") } .onAppear { print("item\(item)") } } } } .listRowInsets(EdgeInsets()) .listStyle(.plain) .navigationTitle("NavTitle") .navigationBarTitleDisplayMode(.inline) } } init() { if #available(iOS 16, *) { var configuration = UICollectionLayoutListConfiguration(appearance: .plain) // 改为firstItemInSection,只有显式设置header才会显示 configuration.headerMode = .firstItemInSection configuration.headerTopPadding = 0 let layout = UICollectionViewCompositionalLayout.list(using: configuration) UICollectionView.appearance(whenContainedInInstancesOf: [UIViewController.self]).collectionViewLayout = layout } } }
内容的提问来源于stack exchange,提问作者akaakoz
相关产品推荐
相关产品推荐

