Áko*_*vai 9 mvvm ios swift swiftui swiftui-navigationstack
对于编程式导航,您之前可以使用NavigationLink(isActive:, destination:, label:) ,当isActive参数为 true时,它将触发导航。在 IOS 16 中,这已被弃用,并引入了NavigationStack、NavigationLink(value:, label:)和NavigationPath 。
要了解这些的用法,请点击链接:
https://developer.apple.com/documentation/swiftui/migration-to-new-navigation-types https://www.hackingwithswift.com/articles/250/whats-new-in-swiftui-for-ios-16(搜索NavigationStack)
我的问题是,如果我想在不同的视图及其 ViewModel 中使用它,我应该如何使用和维护包含导航堆栈内容的数组(如 NavigationPath 对象)?
正如您在下面的代码中看到的,我创建了一个 NavigationPath 对象来将导航堆栈保存在 BaseView 或 BaseView.ViewModel 中。这样我就可以从该 BaseView 到其他页面(Page1、Page2)进行编程导航,这很棒。
但是,如果我转到 Page1 并尝试以编程方式从那里导航到 Page2,我需要访问原始的 NavigationPath 对象,即我在 BaseView 中使用的对象。
访问这个原始对象的最佳方式是什么?
我可能误解了这个新功能的用法,但如果您有任何可能的从 ViewModel 进行编程导航的解决方案,我会很高兴看到它:)
我尝试做的事情:
struct BaseView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
NavigationStack(path: $viewModel.paths) {
VStack {
Button("Page 1", action: viewModel.goToPage1)
Button("Page 2", action: viewModel.goToPage2)
}
.navigationDestination(for: String.self) { stringParam in
Page1(stringParam: stringParam)
}
.navigationDestination(for: Int.self) { intParam in
Page2(intParam: intParam)
}
}
}
}
extension BaseView {
@MainActor class ViewModel: ObservableObject {
@Published var paths = NavigationPath()
func goToPage1() {
let param = "Some random string" // gets the parameter from some calculation or async network call
paths.append(param)
}
func goToPage2() {
let param = 19 // gets the parameter from some calculation or async network call
paths.append(param)
}
}
}
struct Page1: View {
@StateObject var viewModel = ViewModel()
let stringParam: String
var body: some View {
VStack {
Button("Page 2", action: viewModel.goToPage2)
}
}
}
extension Page1 {
@MainActor class ViewModel: ObservableObject {
func goToPage2() {
// Need to add value to the original paths variable in BaseView.ViewModel
}
}
}
struct Page2: View {
@StateObject var viewModel = ViewModel()
let intParam: Int
var body: some View {
Text("\(intParam)")
}
}
extension Page2 {
@MainActor class ViewModel: ObservableObject {
}
}
Run Code Online (Sandbox Code Playgroud)
小智 3
官方迁移指南提供了很多有用的信息。
修饰符navigationDestination(for:destination:)允许对特定数据类型进行自定义处理。
您可以将选定的数据类型“推送”到 上NavigationPath,然后相关navigationDestination块将处理它。
我创建了一些辅助函数来简化新的导航系统。
我将它们存储在一个自定义AppContext类中,您将在下面看到提到的 ( appContext),但当然可以在最适合您自己的代码库的地方放置并引用它们。
/// The current navigation stack.
@Published public var navStack = NavigationPath()
/// Type-erased keyed data stored for a given view.
var navData = Dictionary<String, Any>()
/// Set to `true` the given "show view" bound Bool (i.e. show that view).
/// Optionally, provide data to pass to that view.
public func navigateTo(_ showViewFlag: Binding<Bool>,
_ navData: Dictionary<String, Any>? = nil) {
if let navData { self.navData = navData }
showViewFlag.wrappedValue = true
}
/// Pop & retrieve navigation data for the given key.
/// (Generics undo the type-erasure produced by `navigateTo`)
public func popNavData<T>(_ key: String) -> T {
navData.removeValue(forKey: key)! as! T
}
Run Code Online (Sandbox Code Playgroud)
此destination修改器是官方修改器的更简洁版本navigationDestination:
@ViewBuilder
func destination(`for` show: Binding<Bool>,
_ destination: @escaping () -> some View ) -> some View {
self.navigationDestination(isPresented: show) { DeferView(destination) }
}
Run Code Online (Sandbox Code Playgroud)
它DeferView使用的定义为:
import SwiftUI
public struct DeferView<Content: View>: View {
let content: () -> Content
public init(@ViewBuilder _ content: @escaping () -> Content) { self.content = content }
public var body: some View { content() }
}
Run Code Online (Sandbox Code Playgroud)
所以现在你可以这样做:
// Use the standard bound-bool "show view" var format.
@State var showMyView: Bool
// Code to load the view, e.g. in a Button `action`.
navigateTo($showMyView, ["param1": myData1, "param2", myData2])
// Modifier to handle the view load, e.g. on outermost View inside `body`.
.destination(for: $showMyView) {
MyView(param1: appContext.popNavData("param1"),
param2: appContext.popNavData("param2"),
extraParam: $someOtherSource.info)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5654 次 |
| 最近记录: |