You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:57:34