SwiftUI如何垂直布局两个List,仅保留少量间距?
SwiftUI 消除两个List组件间距方案
我当前的SwiftUI布局包含两个带DisclosureGroup的列表和下方的选择列表:上方是包含两个可展开分组的列表,每个分组展开后有子项和添加按钮;下方是带选择功能的列表,目前两个列表之间存在明显空白间距。
对应的代码如下:
struct HomeView: View { @State private var selectedItem: String? var body: some View { VStack { List { DisclosureGroupWithButton(title: "Group 1", items: ["Item 1", "Item 2", "Item 3"]) DisclosureGroupWithButton(title: "Group 2", items: ["Item A", "Item B", "Item C"]) } .listStyle(SidebarListStyle()) List(selection: self.$selectedItem) { ForEach(["Option 1", "Option 2", "Option 3"], id: \.self) { item in Text(item) .tag(item) } } .frame(maxHeight: .infinity) } } } struct DisclosureGroupWithButton: View { let title: String let items: [String] @State private var isExpanded: Bool = false var body: some View { DisclosureGroup(isExpanded: self.$isExpanded) { ForEach(items, id: \.self) { item in Text(item) } Button("Add Item") { print("\(title) button tapped") } .buttonStyle(.bordered) .padding(.top, 5) } label: { Text(self.title) } } }
我希望底部的List紧邻上方的DisclosureGroup列表,仅保留少量间距(消除空白区域),但尝试使用Spacer等方法均无效果。即使简化为仅两个基础List的布局,同样存在该问题:
struct HomeView: View { @State private var selectedItem: String? var body: some View { List { ForEach(["Option 1", "Option 2", "Option 3"], id: \.self) { item in Text(item) .tag(item) } } List(selection: self.$selectedItem) { ForEach(["Option 1", "Option 2", "Option 3"], id: \.self) { item in Text(item) .tag(item) } } } }
请问如何实现该需求?
解决方案
问题根源在于SwiftUI的List组件默认自带内边距和外部间距,尤其是使用SidebarListStyle时表现更明显。以下是几种可行的解决方式:
方法1:手动抵消List默认间距
通过调整padding的负值抵消List的默认内外间距,同时设置VStack的间距为需要的最小值:
struct HomeView: View { @State private var selectedItem: String? var body: some View { VStack(spacing: 4) // 设置两个List之间的最小间距 { List { DisclosureGroupWithButton(title: "Group 1", items: ["Item 1", "Item 2", "Item 3"]) DisclosureGroupWithButton(title: "Group 2", items: ["Item A", "Item B", "Item C"]) } .listStyle(SidebarListStyle()) .padding(.bottom, -8) // 抵消List底部默认间距 .listRowInsets(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)) // 统一行内边距 List(selection: self.$selectedItem) { ForEach(["Option 1", "Option 2", "Option 3"], id: \.self) { item in Text(item) .tag(item) } } .frame(maxHeight: .infinity) .padding(.top, -8) // 抵消List顶部默认间距 .listRowInsets(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)) } } }
方法2:合并为单个List的多个Section(推荐)
将两个独立List合并为一个List的不同Section,天然消除间距问题,同时保持样式统一:
struct HomeView: View { @State private var selectedItem: String? @State private var group1Expanded = false @State private var group2Expanded = false var body: some View { List(selection: $selectedItem) { Section { DisclosureGroup(isExpanded: $group1Expanded) { ForEach(["Item 1", "Item 2", "Item 3"], id: \.self) { item in Text(item) } Button("Add Item") { print("Group 1 button tapped") } .buttonStyle(.bordered) .padding(.top, 5) } label: { Text("Group 1") } DisclosureGroup(isExpanded: $group2Expanded) { ForEach(["Item A", "Item B", "Item C"], id: \.self) { item in Text(item) } Button("Add Item") { print("Group 2 button tapped") } .buttonStyle(.bordered) .padding(.top, 5) } label: { Text("Group 2") } } Section { ForEach(["Option 1", "Option 2", "Option 3"], id: \.self) { item in Text(item).tag(item) } } } .listStyle(SidebarListStyle()) } }
方法3:固定高度+分隔线
给上方List设置固定高度并裁剪,可选添加细分隔线替代空白:
struct HomeView: View { @State private var selectedItem: String? var body: some View { VStack(spacing: 0) { List { DisclosureGroupWithButton(title: "Group 1", items: ["Item 1", "Item 2", "Item 3"]) DisclosureGroupWithButton(title: "Group 2", items: ["Item A", "Item B", "Item C"]) } .listStyle(SidebarListStyle()) .frame(height: 200) // 根据内容调整固定高度 .clipped() Divider() // 可选:添加细分隔线 .padding(.horizontal, 8) List(selection: self.$selectedItem) { ForEach(["Option 1", "Option 2", "Option 3"], id: \.self) { item in Text(item) .tag(item) } } .frame(maxHeight: .infinity) } } }
推荐使用方法2,它更符合SwiftUI的设计规范,避免了手动调整负边距可能带来的适配问题。
内容的提问来源于stack exchange,提问作者Ser Pounce
相关产品推荐
相关产品推荐

