首页 > 解决方案 > 使用 .edgesIgnoringSafeArea() 时,SwiftUI 布局超出设备范围

问题描述

在 SwiftUI 中出现问题,使用 .edgesIgnoringSafeArea(.bottom) 时,某些视图在垂直方向上的增长大于设备的大小。在 812 像素高的 iPhone 11 Pro 上,我看到大小为 846 的视图。我正在使用 Debug View Hierarchy 来验证它。这已经在 Xcode 11.4.1 和 11.1 上进行了测试,并且存在于两个版本中,并且可能介于两者之间。

我在下面包含了示例代码。

我很确定这是一个 SwiftUI 错误,但想知道是否有人有解决方法。我需要edgesIgnoringSafeArea(.bottom) 代码来绘制TabBar,并在我隐藏自定义标签栏时让ProfileView() 扩展到屏幕底部。

struct ContentView: View {
    var body: some View {
        MainTabView()
    }
}

struct MainTabView : View {

    enum Item : CaseIterable {
        case home
        case resources
        case profile
    }

    @State private var selected : Item = .home

    var body: some View {
        VStack(spacing: 0.0) {
            ZStack {
                HomeView()
                    .zIndex(selected == .home ? 1 : 0)
                
                ResourcesView()
                    .zIndex(selected == .resources ? 1 : 0)

                ProfileView()
                    .zIndex(selected == .profile ? 1 : 0)
            }
          
            // Code here for building and showing/hiding a Toolbar
            // Basically just a HStack with a few buttons in it
        }
        .edgesIgnoringSafeArea(.bottom) // <- This causes the screen to jump to 846
    }
}

struct ProfileView : View {
    @State private var showQuestionnaireView = false

    var body: some View {
        NavigationView {
            ZStack {

                NavigationLink(destination: QuestionnaireView( showQuestionnaireView:$showQuestionnaireView),
                               isActive: $showQuestionnaireView) {
                                Text("Show Questionnaire View")
                }
                .navigationBarTitle("")
                .navigationBarHidden(true)
            }
        }
    }
}

struct QuestionnaireView : View {
    @Binding var showQuestionnaireView : Bool

    var body: some View {
        GeometryReader { screenGeometry in
            ZStack {
                Color.orange
                VStack {
                    Text("Top")
                    Spacer()
                    Text("Bottom")
                }
            }
        }
    }
}

HomeView() 和 ResourcesView() 只是 ProfileView() 的副本,它们做自己的事情。

当您运行它时,您将看到一个按钮,按下该按钮并在 QuestionnaireView 上推送一个隐藏的导航堆栈视图,此视图包含一个带有两个文本字段的 VStack,由于此问题,您将无法看到这两个文本字段。可以理解的是,顶部位于缺口后面,但底部位于屏幕底部。在我的真实项目中,这个问题在运行时很少出现,但是在暗模式和亮模式之间切换会显示出来。在上面的代码中,不需要切换外观。

编辑:FB7677794 对于任何感兴趣的人,自 3 周前提交以来,尚未收到 Apple 的任何更新。

EDIT2:向 MainTabBar 添加了更多代码

更新:这已在 Xcode 12 Beta 2 中修复

标签: layoutswiftui

解决方案


这是由于NavigationView. 当您添加自定义选项卡栏组件时,如下例所示,它限制了底部区域,NavigationView 将正确布局。

使用 Xcode 11.4 / iOS 13.4 测试

演示

struct MainTabView : View {
    var body: some View {
        VStack(spacing: 0.0) {
            ZStack {
                Color(.cyan)
                ProfileView()   // << this injects NavigationView
            }
            HStack { // custom tab bar
                Button(action: {}) { Image(systemName: "1.circle").padding() }
                Button(action: {}) { Image(systemName: "2.circle").padding() }
                Button(action: {}) { Image(systemName: "3.circle").padding() }
            }.padding(.bottom)
        }
        .edgesIgnoringSafeArea(.bottom) // works !!
    }
}

推荐阅读