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

SwiftUI中如何移除Page样式TabView的空白并设置动态高度?

SwiftUI 移除TabView与内部List的空白并适配布局

问题描述

在NavigationStack中嵌套了Page样式的TabView,其下方还有一个List。TabView内部的自定义视图包含水平List,需要解决三个问题:

  • 移除TabView与内部子视图之间的空白
  • 让TabView内的List占满宽度且顶部无内边距
  • 动态设置TabView高度适配子视图,避免硬编码高度

原始代码:

import SwiftUI

struct CustomView: View {
    var dataArray: [String]

    var body: some View {
        List {
            LazyHStack {
                ForEach(dataArray, id: \.self) { item in
                    Button("\(item)") {
                    }
                    .buttonStyle(.bordered)
                }
            }
        
        }
        .scrollDisabled(true)
    }
}

struct ContentView: View {
    struct Sea: Hashable, Identifiable {
        let name: String
        let id = UUID()
    }

    struct OceanRegion: Identifiable {
        let name: String
        let seas: [Sea]
        let id = UUID()
    }

    private let oceanRegions: [OceanRegion] = [
        OceanRegion(name: "Pacific",
                    seas: [Sea(name: "Australasian Mediterranean"),
                           Sea(name: "Philippine"),
                           Sea(name: "Coral"),
                           Sea(name: "South China")]),
        OceanRegion(name: "Atlantic",
                    seas: [Sea(name: "American Mediterranean"),
                           Sea(name: "Sargasso"),
                           Sea(name: "Caribbean")]),
        OceanRegion(name: "Indian",
                    seas: [Sea(name: "Bay of Bengal")]),
        OceanRegion(name: "Southern",
                    seas: [Sea(name: "Weddell")]),
        OceanRegion(name: "Arctic",
                    seas: [Sea(name: "Greenland")])
    ]

    @State private var singleSelection: UUID?

    @State private var weekIndex = 0
    @State private var weeks = [ -1, 0, 1 ]

    @State private var dataArray1 = ["1","2","3","4","5","6","7"]
    @State private var dataArray2 = ["8","9","10","11","12","13","14"]
    @State private var dataArray3 = ["15","16","17","18","19","20","21"]

    var body: some View {
        NavigationStack {
            VStack {
                TabView(selection: $weekIndex) {
                    CustomView(dataArray: dataArray1).tag(weeks[0])
                    CustomView(dataArray: dataArray2).tag(weeks[1])
                    CustomView(dataArray: dataArray3).tag(weeks[2])
                }
                .tabViewStyle(.page(indexDisplayMode: .never))
                .indexViewStyle(.page(backgroundDisplayMode: .never))
            }
                
            List(selection: $singleSelection) {
                ForEach(oceanRegions) { region in
                    Section(header: Text("Major \(region.name) Ocean Seas")) {
                        ForEach(region.seas) { sea in
                            NavigationLink(destination: EmptyView()) {
                                Text(sea.name)
                            }
                        }
                    }
                }
            }
            .navigationTitle("Oceans and Seas")
            .toolbar {
                ToolbarItem {
                    Button(action: {}) {
                        Label("Add", systemImage: "plus")
                    }
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

解决方案

核心修改思路

  1. 移除List默认布局带来的内边距与空白:SwiftUI的List自带默认内边距、行高和间距,需通过样式配置清除
  2. 让TabView动态适配高度:使用fixedSize让TabView根据内容自动调整高度,避免硬编码
  3. 清除容器视图的默认间距:调整VStack的spacing属性,消除TabView与下方List的空隙

修改后的完整代码

import SwiftUI

struct CustomView: View {
    var dataArray: [String]

    var body: some View {
        // 方案一:直接用LazyHStack替代List,彻底避免List默认布局的空白
        LazyHStack(spacing: 8) {
            ForEach(dataArray, id: \.self) { item in
                Button("\(item)") {
                }
                .buttonStyle(.bordered)
            }
        }
        .padding(.vertical, 8)
        .frame(maxWidth: .infinity)
        
        // 方案二:若必须保留List,使用以下配置清除空白
        /*
        List {
            LazyHStack(spacing: 8) {
                ForEach(dataArray, id: \.self) { item in
                    Button("\(item)") {
                    }
                    .buttonStyle(.bordered)
                }
            }
            .listRowInsets(EdgeInsets()) // 清除行内边距
        }
        .listStyle(.plain)
        .scrollDisabled(true)
        .environment(\.defaultMinListRowHeight, 0) // 强制最小行高为0
        .padding(.horizontal, 0)
        */
    }
}

struct ContentView: View {
    struct Sea: Hashable, Identifiable {
        let name: String
        let id = UUID()
    }

    struct OceanRegion: Identifiable {
        let name: String
        let seas: [Sea]
        let id = UUID()
    }

    private let oceanRegions: [OceanRegion] = [
        OceanRegion(name: "Pacific",
                    seas: [Sea(name: "Australasian Mediterranean"),
                           Sea(name: "Philippine"),
                           Sea(name: "Coral"),
                           Sea(name: "South China")]),
        OceanRegion(name: "Atlantic",
                    seas: [Sea(name: "American Mediterranean"),
                           Sea(name: "Sargasso"),
                           Sea(name: "Caribbean")]),
        OceanRegion(name: "Indian",
                    seas: [Sea(name: "Bay of Bengal")]),
        OceanRegion(name: "Southern",
                    seas: [Sea(name: "Weddell")]),
        OceanRegion(name: "Arctic",
                    seas: [Sea(name: "Greenland")])
    ]

    @State private var singleSelection: UUID?

    @State private var weekIndex = 0
    @State private var weeks = [ -1, 0, 1 ]

    @State private var dataArray1 = ["1","2","3","4","5","6","7"]
    @State private var dataArray2 = ["8","9","10","11","12","13","14"]
    @State private var dataArray3 = ["15","16","17","18","19","20","21"]

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) { // 清除VStack默认间距
                TabView(selection: $weekIndex) {
                    CustomView(dataArray: dataArray1).tag(weeks[0])
                    CustomView(dataArray: dataArray2).tag(weeks[1])
                    CustomView(dataArray: dataArray3).tag(weeks[2])
                }
                .tabViewStyle(.page(indexDisplayMode: .never))
                .indexViewStyle(.page(backgroundDisplayMode: .never))
                .fixedSize(horizontal: false, vertical: true) // 动态适配高度
                .frame(maxWidth: .infinity) // 强制铺满宽度
                
                List(selection: $singleSelection) {
                    ForEach(oceanRegions) { region in
                        Section(header: Text("Major \(region.name) Ocean Seas")) {
                            ForEach(region.seas) { sea in
                                NavigationLink(destination: EmptyView()) {
                                    Text(sea.name)
                                }
                            }
                        }
                    }
                }
                .navigationTitle("Oceans and Seas")
                .toolbar {
                    ToolbarItem {
                        Button(action: {}) {
                            Label("Add", systemImage: "plus")
                        }
                    }
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

关键修改点说明

  • CustomView优化:用LazyHStack直接替代List,避免List默认的内边距和行高;若必须保留List,通过listRowInsets、defaultMinListRowHeight等配置清除空白
  • TabView动态高度:添加fixedSize(horizontal: false, vertical: true)让TabView根据内容自动计算高度
  • 容器间距清除:VStack设置spacing: 0,消除TabView与下方List之间的空隙
  • 宽度适配:添加frame(maxWidth: .infinity)确保TabView及其子视图铺满屏幕宽度

内容的提问来源于stack exchange,提问作者s_diaconu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 04:15:24