SwiftUI模态Sheet底部出现多余空白的解决方法咨询
问题描述
我开发了一个包含2个标签页的基础TabView,其中Tab 2的按钮可唤起嵌入在NavigationStack内、带有工具栏的Page Style TabView模态Sheet。添加NavigationStack后,Sheet页面底部出现了多余空白区域。我已尝试在多个位置使用.ignoreSafeArea(edges: .bottom),但问题仍未解决。请问我遗漏了什么?如何消除该多余空白?NavigationStack的位置是否有误?
开发环境:iOS 16.1、Xcode 14.2
代码如下:
struct HomeView: View { @State private var pageIndex = 0 var body: some View { TabView(selection: $pageIndex) { PageOne() .tabItem { Label("Page 1", systemImage: "star") }.tag(0) PageTwo() .tabItem { Label("Page 2", systemImage: "bookmark") }.tag(1) } } } struct PageOne: View { var body: some View { VStack { Text("Page 1") } } } struct PageTwo: View { @State private var sheetIsShowing = false var body: some View { VStack { Text("Page 2") Button("Show Sheet") { self.sheetIsShowing.toggle() } } .fullScreenCover(isPresented: $sheetIsShowing) { SheetView(sheetIsShowing: $sheetIsShowing) } } } struct SheetView: View { @Binding var sheetIsShowing: Bool var body: some View { NavigationStack { TabView { SheetTabView1() SheetTabView2() } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { self.sheetIsShowing.toggle() } label: { Text("Cancel") } } } } .ignoresSafeArea(edges: .bottom) } } struct SheetTabView1: View { @State private var text1 = "" @State private var text2 = "" var body: some View { List { TextField("Enter Text", text: $text1) TextField("Enter Text", text: $text2) } } } struct SheetTabView2: View { @State private var text1 = "" @State private var text2 = "" var body: some View { List { TextField("Enter Text", text: $text1) TextField("Enter Text", text: $text2) } } }
问题截图:
解决方法
这个问题的核心是NavigationStack与TabView的层级冲突,以及List的安全区域适配逻辑,调整层级并针对性设置即可解决:
- 调整NavigationStack的嵌套层级:将NavigationStack从包裹整个TabView,改为嵌套在每个Sheet子页面(SheetTabView1、SheetTabView2)内部。PageTabViewStyle的TabView本身会处理页面布局,外层套NavigationStack会导致系统安全区域计算混乱。
- 给List添加底部安全区域忽略:在每个Sheet子页面的List上添加
.ignoresSafeArea(edges: .bottom),让List直接填充底部空白区域。 - 移除无效的全局ignoreSafeArea:删除SheetView中加在NavigationStack外层的
.ignoresSafeArea(edges: .bottom),该设置在新层级下无效。
修改后的完整代码:
struct HomeView: View { @State private var pageIndex = 0 var body: some View { TabView(selection: $pageIndex) { PageOne() .tabItem { Label("Page 1", systemImage: "star") }.tag(0) PageTwo() .tabItem { Label("Page 2", systemImage: "bookmark") }.tag(1) } } } struct PageOne: View { var body: some View { VStack { Text("Page 1") } } } struct PageTwo: View { @State private var sheetIsShowing = false var body: some View { VStack { Text("Page 2") Button("Show Sheet") { self.sheetIsShowing.toggle() } } .fullScreenCover(isPresented: $sheetIsShowing) { SheetView(sheetIsShowing: $sheetIsShowing) } } } struct SheetView: View { @Binding var sheetIsShowing: Bool var body: some View { TabView { SheetTabView1() SheetTabView2() } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { self.sheetIsShowing.toggle() } label: { Text("Cancel") } } } } } struct SheetTabView1: View { @State private var text1 = "" @State private var text2 = "" var body: some View { NavigationStack { List { TextField("Enter Text", text: $text1) TextField("Enter Text", text: $text2) } .ignoresSafeArea(edges: .bottom) } } } struct SheetTabView2: View { @State private var text1 = "" @State private var text2 = "" var body: some View { NavigationStack { List { TextField("Enter Text", text: $text1) TextField("Enter Text", text: $text2) } .ignoresSafeArea(edges: .bottom) } } }
补充:如果不需要每个子页面独立的导航逻辑,也可以将NavigationStack放在TabView内部(作为TabView的直接父视图),同时给TabView添加.ignoresSafeArea(edges: .bottom),但前者的结构更灵活,便于后续扩展每个页面的导航功能。
内容的提问来源于stack exchange,提问作者sandPitPilot
相关产品推荐
相关产品推荐

