layout - 使用 .edgesIgnoringSafeArea() 时,SwiftUI 布局会超出设备边界

标签 layout swiftui

SwiftUI 中存在一个问题,即使用 .edgesIgnoringSafeArea(.bottom) 时,某些 View 在垂直方向上变得比设备大小更大。在高度为 812 像素的 iPhone 11 Pro 上,我看到尺寸为 846 的 View 。我正在使用调试 View 层次结构来验证它。这已经在 Xcode 11.4.1 和 11.1 上进行了测试,并且存在于两个版本中,并且可能存在于两者之间。

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

我很确定这是一个 SwiftUI 错误,但想知道是否有人有解决方法。我需要 EdgeIgnoringSafeArea(.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() 的副本,它们做自己的事情。

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

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

EDIT2:向 MainTabBar 添加了更多代码

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

最佳答案

阅读更新后的问题后,我做了一些更改并尝试制作一个小型演示。在此,我使用与之前相同的方法,将 NavigationView 放入主选项卡 View 中,这样您就不必在每次进入或离开主选项卡 View 时隐藏和显示。

import SwiftUI

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 {
        NavigationView {
            VStack(spacing: 0.0) {
                ZStack {
                    Group {
                        HomeView()
                            .zIndex(selected == .home ? 1 : 0)

                        ResourcesView()
                            .zIndex(selected == .resources ? 1 : 0)

                        ProfileView()
                            .zIndex(selected == .profile ? 1 : 0)

                    }
                    .frame(minWidth: .zero, maxWidth: .infinity, minHeight: .zero, maxHeight: .infinity)
                    .background(Color.white)

                }

                HStack {
                    Group {
                        Image(systemName: "house.fill")
                            .onTapGesture {
                                self.selected = .home
                        }

                        Spacer()

                        Image(systemName: "plus.app.fill")
                            .onTapGesture {
                                self.selected = .resources
                        }

                        Spacer()

                        Image(systemName: "questionmark.square.fill")
                            .onTapGesture {
                                self.selected = .profile
                        }
                    }
                    .padding(.horizontal, 30)
                }
                .frame(height: 40)
                .foregroundColor(Color.white)
                .background(Color.gray)


                // 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")
                }
            }
            .edgesIgnoringSafeArea(.bottom)
        }
    }
}

struct HomeView: View {
    var body: some View {
        NavigationLink(destination: SecondView()) {
            Text("Home View")
        }
    }
}

struct ResourcesView: View {
    var body: some View {
        NavigationLink(destination: SecondView()) {
            Text("Resources View")
        }
    }
}

struct SecondView: View {
    var body: some View {
        Text("Second view in navigation")
            .background(Color.black)
            .foregroundColor(.white)
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
        .previewDevice(PreviewDevice(rawValue: "iPhone 11"))
    }
}

关于layout - 使用 .edgesIgnoringSafeArea() 时,SwiftUI 布局会超出设备边界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61471262/

相关文章:

html - div 内的 float div 具有奇怪的间距

swift - 我必须在 SwiftUI 中使用 ObservableObject 吗?

swiftui - 使用 SwiftUI 的 relativeWidth 仅在框架 View 内有效

swift - 如何在 Live Activity (ActivityKit) 中获取图像 - SwiftUI

java - 我应该为这个 Java GUI 作业使用什么样的布局?

ios - View 的 Frame 被调用两次并导致剪切错误

android - Xamarin.Forms 布局如何转换为特定于平台的布局?

html - 如何使用 3 个元素进行布局,其中 1 个元素可调整大小

xcode - 针对目标 macOS 10.15 使用 Xcode 12 构建错误

ios - 尝试使用几何阅读器和导航栏获得全宽 View - SwiftUI