当前位置: 首页 > 知识库问答 >
问题:

如何使用 SwiftUI 弹出到根视图?

徐昊焜
2023-03-14

最后,使用Beta 5,我们可以通过编程方式弹出到父视图。然而,在我的应用程序中有几个地方,视图有一个“保存”按钮,它结束了一个多步骤的过程并返回到开始。在UIKit中,我使用popToRootViewController(),但我无法在SwiftUI中找到同样的方法。

下面是我试图实现的模式的一个简单例子。

我该怎么做?

import SwiftUI

struct DetailViewB: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    var body: some View {
        VStack {
            Text("This is Detail View B.")

            Button(action: { self.presentationMode.value.dismiss() } )
            { Text("Pop to Detail View A.") }

            Button(action: { /* How to do equivalent to popToRootViewController() here?? */ } )
            { Text("Pop two levels to Master View.") }

        }
    }
}

struct DetailViewA: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    var body: some View {
        VStack {
            Text("This is Detail View A.")

            NavigationLink(destination: DetailViewB() )
            { Text("Push to Detail View B.") }

            Button(action: { self.presentationMode.value.dismiss() } )
            { Text("Pop one level to Master.") }
        }
    }
}

struct MasterView: View {
    var body: some View {
        VStack {
            Text("This is Master View.")

            NavigationLink(destination: DetailViewA() )
            { Text("Push to Detail View A.") }
        }
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            MasterView()
        }
    }
}

共有3个答案

谷奕
2023-03-14

由于目前SwiftUI仍在后台使用UINavigationController,因此也可以调用其< code > popToRootViewController(animated:)函数。您只需在视图控制器层次结构中搜索UINavigationController,如下所示:

struct NavigationUtil {
  static func popToRootView() {
    findNavigationController(viewController: UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController)?
      .popToRootViewController(animated: true)
  }

  static func findNavigationController(viewController: UIViewController?) -> UINavigationController? {
    guard let viewController = viewController else {
      return nil
    }

    if let navigationController = viewController as? UINavigationController {
      return navigationController
    }

    for childViewController in viewController.children {
      return findNavigationController(viewController: childViewController)
    }

    return nil
  }
}

像这样使用它:

struct ContentView: View {
    var body: some View {
      NavigationView { DummyView(number: 1) }
    }
}

struct DummyView: View {
  let number: Int

  var body: some View {
    VStack(spacing: 10) {
      Text("This is view \(number)")
      NavigationLink(destination: DummyView(number: number + 1)) {
        Text("Go to view \(number + 1)")
      }
      Button(action: { NavigationUtil.popToRootView() }) {
        Text("Or go to root view!")
      }
    }
  }
}
孙洋
2023-03-14

当然,malhal拥有解决方案的关键,但是对我来说,将绑定作为参数传递给视图是不切实际的。正如Imthath所指出的,环境是一种更好的方式。

这是另一种仿照Apple发布的disiss()方法弹出到之前的View的方法。

定义环境的扩展:

struct RootPresentationModeKey: EnvironmentKey {
    static let defaultValue: Binding<RootPresentationMode> = .constant(RootPresentationMode())
}

extension EnvironmentValues {
    var rootPresentationMode: Binding<RootPresentationMode> {
        get { return self[RootPresentationModeKey.self] }
        set { self[RootPresentationModeKey.self] = newValue }
    }
}

typealias RootPresentationMode = Bool

extension RootPresentationMode {
    
    public mutating func dismiss() {
        self.toggle()
    }
}

用法:

>

  • .environment(\.rootPresentationMode,self.$isPresented)添加到根导航视图中,其中 isBool用于显示第一个子视图。

    . NavigationViewStyle(StackNavigationViewStyle())修饰符添加到根NavigationView,或将. isDetailLink(false)添加到第一个子视图的NavigationLink

    添加<代码> @环境(\。root presentation mode)private var root presentation mode 到任何子视图,从那里应该执行到根的pop。

    最后,从子视图调用< code > self . root presentation mode . wrapped value . dissolve()将弹出到根视图。

    我已经在GitHub上发布了一个完整的工作示例。

  • 乜烨霖
    2023-03-14

    导航链接上将视图修饰符设置为“取消详细信息链接”为 false 是使“从”弹出到根目录“正常工作的关键。是删除链接在默认情况下为 true,并且适用于包含的视图。例如,在 iPad 横向上,“拆分”视图是分开的,而“删除链接”可确保目标视图显示在右侧。将“取消详细信息链接”设置为 false 意味着目标视图将始终推送到导航堆栈上;因此总是可以弹出。

    除了在< code>NavigationLink上将< code>isDetailLink设置为< code>false之外,还要将< code>isActive绑定传递给每个后续的目标视图。最后,当您想要弹出到根视图时,将值设置为< code>false,它将自动弹出所有内容:

    import SwiftUI
    
    struct ContentView: View {
        @State var isActive : Bool = false
    
        var body: some View {
            NavigationView {
                NavigationLink(
                    destination: ContentView2(rootIsActive: self.$isActive),
                    isActive: self.$isActive
                ) {
                    Text("Hello, World!")
                }
                .isDetailLink(false)
                .navigationBarTitle("Root")
            }
        }
    }
    
    struct ContentView2: View {
        @Binding var rootIsActive : Bool
    
        var body: some View {
            NavigationLink(destination: ContentView3(shouldPopToRootView: self.$rootIsActive)) {
                Text("Hello, World #2!")
            }
            .isDetailLink(false)
            .navigationBarTitle("Two")
        }
    }
    
    struct ContentView3: View {
        @Binding var shouldPopToRootView : Bool
    
        var body: some View {
            VStack {
                Text("Hello, World #3!")
                Button (action: { self.shouldPopToRootView = false } ){
                    Text("Pop to root")
                }
            }.navigationBarTitle("Three")
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    
     类似资料:
    • 问题内容: 最后,现在有了Beta 5,我们可以以编程方式弹出到父视图。但是,在我的应用程序中,有几个地方视图都有一个“保存”按钮,该按钮可以结束几个步骤并返回到开始。在UIKit中,我使用popToRootViewController(),但是我一直无法找到在SwiftUI中执行相同操作的方法。 以下是我尝试实现的模式的简单示例。有任何想法吗? 问题答案: 设置视图调节到一个关键是让弹出到根的工

    • 问题内容: 我正在尝试使用以下代码弹出到根视图控制器: 这通常可行,但是当当前视图是模式视图时,尝试使用此代码时出现错误。在这种情况下,我该如何跳回到根视图控制器? 提前致谢。 问题答案: 您可以检查当前控制器是否存在,如果存在,则将其关闭,然后直接转到当前控制器。

    • 我对中的有一个问题。 下面是我的代码: 问题:在中按下时,会像它应该的那样消失,取而代之。但是,并不会消失,而是停留在视图B的顶部。 当更改为时,如何强制关闭?请注意,也可以由以外的其他视图更改,因此只将传递给并在单击时将其设置为false并不能完成此工作。

    • 问题内容: 我找不到有关使用SwiftUI 以* 编程 方式 弹出 或 关闭 所显示视图的任何方式的任何参考。 * 在我看来,唯一的方法是对模式使用已经集成的幻灯片dow操作(以及是否/如何禁用此功能?),以及对导航堆栈使用后退按钮。 有人知道解决方案吗?您知道这是一个错误还是会一直保持这种状态? 问题答案: 本示例使用Beta 5版本说明中记录的新环境var,该环境使用了value属性。在更高的

    • 问题内容: 我可以做一个静态列表 但是,如何从数组中动态生成元素列表?我尝试了以下操作,但出现错误: 包含控制流语句的闭包不能与函数生成器“ ViewBuilder”一起使用 有什么解决办法吗?我要完成的工作是一个列表,其中包含不是静态输入的动态元素集。 问题答案: 看起来答案与将我的视图包装在其中有关 这样,我现在可以从服务器获取视图数据并进行组合。而且,仅在需要时才实例化它们。

    • 问题内容: 我有一个SwiftUI视图,其中包含一个名为的EnvironmentObject 。然后,它读取其方法中的值。我希望这可以将我的视图绑定到该属性,以便在属性更新时重新呈现该属性,但这似乎没有发生。 这是一个错误吗?如果没有,将视图绑定到SwiftUI中环境对象的嵌套属性的惯用方式是什么? 具体来说,我的模型看起来像这样… 我的观点看起来像这样… 当我运行应用程序并单击标签时,属性会增加