iPad 弹出窗口中的 NavigationView 在 SwiftUI 中无法正常工作

Sor*_*ica 9 ipad ios swiftui

我有以下代码在点击按钮时显示弹出窗口:

struct ContentView: View {

    @State private var show = false

    var body: some View {

        Button("Open") {
            self.show.toggle()
        }.popover(isPresented: $show, content: {
//            NavigationView {
                ScrollView {
                    ForEach(0...10, id: \.self) {_ in
                        Text("Test popover ...")
                    }.padding()
                }
//            }
        })

    }
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

如果我NavigationView在 popover 的内容中添加一个,那么我会得到这个:

在此处输入图片说明

知道为什么会这样吗?

如果我为内容设置了一个固定的框架,它工作正常,但我不想这样做,因为我希望弹出框根据其内容调整大小。

ggr*_*uen 9

阿斯佩里的回答很好也很彻底,但我想我应该为我们当中比较懒的人添加一个。

微小的弹出窗口是 iPadOS 13.4 中引入的一个错误(弹出窗口按照您在 13.0.x - 13.3.x 中的预期出现)。我就此提交了 FB7640734,该报告目前显示“不到 10 个”类似的报告,并且仍然处于开放状态。

我在使用运行在 iOS、iPadOS 和 Mac Catalyst 上的 SwiftUI 编写的生产应用程序中使用的简单解决方法是在您的 NavigationView 之后添加以下内容:

.frame(minWidth: 320, idealWidth: 400, maxWidth: nil, minHeight: 500, idealHeight: 700, maxHeight: nil, alignment: .top)
Run Code Online (Sandbox Code Playgroud)

即在OP示例代码的上下文中:

struct ContentView: View {

    @State private var show = false

    var body: some View {

        Button("Open") {
            self.show.toggle()
        }.popover(isPresented: $show, content: {
            NavigationView {
                ScrollView {
                    ForEach(0...10, id: \.self) {_ in
                        Text("Test popover ...")
                    }.padding()
                }
            }.frame(minWidth: 320, idealWidth: 400, maxWidth: nil,
                    minHeight: 500, idealHeight: 700, maxHeight: nil,
                    alignment: .top)
        })

    }
}
Run Code Online (Sandbox Code Playgroud)

这设置了一个大小合适的弹出窗口,它将在 320-400 点宽和 500x700 点高之间扩展,这实际上对于弹出窗口来说是一个很好的尺寸(任何更大的尺寸,您可能应该使用除弹出窗口之外的其他东西)。


Asp*_*eri 8

可能在 iPad 上,他们在尺寸检测方面遇到了先有鸡还是先有蛋的问题,所以只是最终确定了最小值。

无论如何,解决方案是.frame显式设置,或者使用预定义值(对于 iPad 来说还不错),或者动态计算(例如从外框通过GeometryReader

这是一个例子。使用 Xcode 12 / iPadOS 14 进行测试

演示

struct TestPopover: View {

    @State private var show = false

    var body: some View {
        GeometryReader { gp in
            VStack {
                Button("Open") {
                    self.show.toggle()
                }.popover(isPresented: $show, content: {
                    NavigationView {
                        ScrollView {   // or List
                            ForEach(0...10, id: \.self) {_ in
                                Text("Test popover ...")
                            }.padding()
                        }
                        .navigationBarTitle("Test", displayMode: .inline)
                    }
                    .frame(width: gp.size.width / 3, height: gp.size.height / 3)
                })
            }.frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

变体 2:部分根据外部尺寸计算,部分根据内部尺寸计算。

演示2

struct TestPopover: View {

    @State private var show = false
    @State private var popoverWidth = CGFloat(100)

    var body: some View {
        GeometryReader { gp in
            VStack {
                Button("Open") {
                    self.show.toggle()
                }.popover(isPresented: $show, content: {
                    NavigationView {
                        ScrollView {   // or List
                            ForEach(0...10, id: \.self) {_ in
                                Text("Test popover ...").fixedSize()
                            }.padding()
                            .background(GeometryReader {
                                Color.clear
                                    .preference(key: ViewWidthKey.self, value: $0.frame(in: .local).size.width)
                            })
                            .onPreferenceChange(ViewWidthKey.self) {
                                self.popoverWidth = $0
                            }
                        }
                        .navigationBarTitle("Test", displayMode: .inline)
                    }
                    .frame(width: self.popoverWidth, height: gp.size.height / 3)
                })
            }.frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}

struct ViewWidthKey: PreferenceKey {
    typealias Value = CGFloat
    static var defaultValue = CGFloat.zero
    static func reduce(value: inout Value, nextValue: () -> Value) {
        value += nextValue()
    }
}

Run Code Online (Sandbox Code Playgroud)