首页 > 解决方案 > 为根 NavigationView 应用基于 Horizo​​ntalSizeClass 的 navigationStyle 并保留导航堆栈

问题描述

在应用程序启动时,我想获得 Horizo​​ntalSizeClass 并根据它是紧凑的还是常规的,将导航样式应用于我的根导航视图,如下所示:

import SwiftUI

@main
struct MyApp: App {
    @Environment(\.horizontalSizeClass) var sizeClass

    var body: some Scene {
        WindowGroup {
            if sizeClass == .compact {
                NavigationView {
                    Text("Compact size class inside stack navigation style")
                }
                .navigationViewStyle(StackNavigationViewStyle())
            } else {
                NavigationView {
                    Text("Regular size class inside default navigation style")
                }
            }
        }
    }
}

但是,在这种情况下sizeClass总是返回。nil

我如何能

  1. 确定水平尺寸类在根视图上是紧凑的还是规则的,以及
  2. 使导航样式在任何时候都适应大小类

我的应用程序针对 iPhone 和 iPad 的 iOS 14。

非常感谢任何帮助或适应整个应用程序大小类更改的不同方法。

更新 1

我尝试了使用ViewModifier或创建自定义视图并在其正文中添加导航的建议,如下所示:

import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            MyRootView()
        }
    }
}

struct MyRootView: View {
    @Environment(\.horizontalSizeClass) var sizeClass

    var body: some View {
        if sizeClass == .compact {
            NavigationView {
                Text("Compact size class inside stack navigation style")
            }
            .navigationViewStyle(StackNavigationViewStyle())
        } else {
            NavigationView {
                Text("Regular size class inside default navigation style")
            }
        }
    }
}

但是,每次sizeClass更改时,导航堆栈都会弹出到根视图。有没有办法保留堆栈?例如:如果用户在导航中的深度为 5 级,并且sizeClass更改,更改导航样式同时保持可见屏幕?

谢谢!

更新 2

我能够找到一个 WWDC 会话来解释我想要什么,但它在 UIKit 中。

请参阅此处的 18:35:https ://developer.apple.com/wwdc20/10105

我正在尝试在 SwiftUI 中实现相同的目标(在将尺寸类更改为紧凑时保持用户选择的屏幕)。

根据会议,UISplitViewController支持这一点,因为在详细视图中有Restorableand的概念。Restore我找不到在 SwiftUI 中执行此操作的方法。

标签: swiftuiswiftui-navigationview

解决方案


是的,忘记了导航视图。您可以尝试这样的事情(使用“https://matteo-pucinelli.medium.com/conditionally-apply-modifiers-in-swiftui-51c1cf7f61d1”中的代码)

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

extension View {
    @ViewBuilder
    func ifCondition<TrueContent: View, FalseContent: View>(_ condition: Bool, then trueContent: (Self) -> TrueContent, else falseContent: (Self) -> FalseContent) -> some View {
        if condition {
            trueContent(self)
        } else {
            falseContent(self)
        }
    }
}

struct ContentView: View {
    @Environment(\.horizontalSizeClass) var sizeClass
    
    var body: some View {
        NavigationView {
            if sizeClass == .compact {
                Text("Compact size class inside stack navigation style")
            } else {
                Text("Regular size class inside default navigation style")
            }
        }
        .ifCondition(sizeClass == .compact) { nv in
            nv.navigationViewStyle(StackNavigationViewStyle())
        } else: { nv in
            nv.navigationViewStyle(DefaultNavigationViewStyle())
        }
    }
}

推荐阅读