ios SwiftUI NavigationLink在大小类更改时被销毁

7jmck4yq  于 2023-08-08  发布在  iOS
关注(0)|答案(1)|浏览(168)

在我们的应用中,我们使用@Environment(\.verticalSizeClass)@Environment(\.horizontalSizeClass)观察大小类的变化。这样做很好,当旋转设备时,我们实现了预期的布局。
问题在于应用程序导航到另一个屏幕时。如果我在人像模式下的MainScreen上,然后导航到DetailScreen,然后旋转设备以横向应用程序返回MainScreen。由于DetailScreen中的旋转,当应用程序重绘MainScreen时,NavigationLink似乎被破坏了。
下面是与我们使用的代码类似的简化代码:

struct MainScreen: View {
    @Environment(\.verticalSizeClass) var verticalSizeClass
    @Environment(\.horizontalSizeClass) var horizontalSizeClass

    var body: some View {
        NavigationView {
            if horizontalSizeClass == .regular && verticalSizeClass == .compact {
                VStack {
                    // other views..
                    NavigationLink(
                        destination: { DetailScreen() },
                        label: { Text("Go to Details Screen") }
                    // other views..
                }
            } else {
                HStack {
                    // other views..
                    NavigationLink(
                        destination: { DetailScreen() },
                        label: { Text("Go to Details Screen") }
                    // other views..
                }
            }
        }
        .navigationViewStyle(.stack)
    }
}

struct DetailScreen: View {
    @Environment(\.verticalSizeClass) var verticalSizeClass
    @Environment(\.horizontalSizeClass) var horizontalSizeClass

    var body: some View {
        Text("Details Screen")
        // Some views that also changes layout base on the verticalSizeClass and horizontalSizeClass
    }
}

字符串
是否有人遇到此问题并能够解决?iOS15对我们的应用程序提供支持。

1dkrff03

1dkrff031#

这是一个相当丑陋的解决方案,但唉,这可能就是为什么NavigationView被弃用的原因。
这个想法是跟踪您在if的哪个分支。每个分支中只有一个NavigationLink,您可以将一些状态传递给isActive参数。

@State var branch1 = false
@State var branch2 = false

字符串
然后使用一些逻辑来说明,如果第一个链接是活动的,则显示第一个链接,而不管大小类是什么,第二个链接也是如此。并且如果两者都不是活动的,则根据大小类显示适当的链接。

var shouldShowVStack: Bool {
    horizontalSizeClass == .compact && verticalSizeClass == .regular
}
if (branch1 || shouldShowVStack) && !branch2 {
    VStack {
        NavigationLink("Go to Details Screen", destination: DetailScreen(), isActive: $branch1)
    }
} else if (branch2 || !shouldShowHStack) && !branch1 {
    HStack {
        NavigationLink("Go to Details Screen landscape", destination: DetailScreen(), isActive: $branch1)
    }
}

的数据
如果在每个分支中有多个NavigationLink,那么更方便的做法是像下面这样对NavigationLink进行 Package :

struct MyNavigationLink<Destination: View>: View {
    
    let destination: () -> Destination
    let label: LocalizedStringKey
    @Binding var isInBranch: Bool
    
    internal init(_ label: LocalizedStringKey, isInBranch: Binding<Bool>, destination: @escaping () -> Destination) {
        self.label = label
        self._isInBranch = isInBranch
        self.destination = destination
    }
    
    var body: some View {
        NavigationLink(label) {
            destination()
                .onAppear {
                    isInBranch = true
                }
                .onDisappear {
                    isInBranch = false
                }
        }
        // or use onChange(of: isActive)
    }
}


当然,如果iOS 16可用,您应该使用NavigationStack。添加适当的if #unavailable来处理此问题。

相关问题