【问题标题】:Dismiss view from view model [MODAL PAGE]从视图模型中关闭视图 [MODAL PAGE]
【发布时间】:2020-03-24 22:55:39
【问题描述】:

我正在使用 swiftUI 并结合,我的虚拟机中有一些业务逻辑。有些结果不得不否定我的看法。

我在某些视图中使用过这个:

@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

self.presentationMode.wrappedValue.dismiss()

我想在我的视图模型中使用类似的东西。

【问题讨论】:

  • 请详细说明您的问题以及您想要实现的目标。
  • 您不会在SwiftUI 中以命令式 的方式进行解雇。相反,您可以使用 .sheet 类型的视图,将其绑定到一个布尔属性,该属性将从该视图模型中发生变异。

标签: swift swiftui combine


【解决方案1】:

如果你想让它变得简单,那么只需在 viewModel 中创建一个名为 goBack 的 Bool 类型的 @Published 变量,并在需要时将其更改为 true,如果该 bool 在更改时为 true,则在视图中使用 .onChange 修饰符运行presentationMode.wrappedValue.dismiss()。

class ViewModel: ObservableObject {
  @Published var goBack: Bool = false
  
  fun itWillToggleGoBack() {
    goBack.toggle()
  }
}


struct MyView {
  @StateObject var vm = ViewModel()
  @Environment(\.presentationMode) var presentationMode

  var body: some View {
    Text("Any kind of view")
      .onChange(of: vm.goBack) { goBack in 
         if goBack {
           self.presentationMode.wrappedValue.dismiss()
         }
      }
  }
}

【讨论】:

    【解决方案2】:

    您不会在 SwiftUI 中以命令式的方式进行解雇。相反,您可以通过将 .sheet 视图绑定到一个布尔属性来使用它,该属性将从该视图模型中发生变异。

    编辑:

    回答后续问题后 question, 我想出了一个不同的方法。如果解雇是很好的 实际上需要从模态呈现的View 内部完成 自己。

    您可以通过实现您的自定义Publisher 来实现这一点,它将使用.send() 方法允许您向订阅者发送特定值(在本例中为您的View)。您将使用 SwiftUIView 协议上定义的 onReceive(_:perform:) 方法订阅您定义的自定义 Publisher 的输出流。在perform 操作闭包中,您可以访问发布者的最新发出值,您将实际解除View

    理论说的够多了,可以看代码,应该不难理解,如下:

    import Foundation
    import Combine
    
    class ViewModel: ObservableObject {
        var viewDismissalModePublisher = PassthroughSubject<Bool, Never>()
        private var shouldDismissView = false {
            didSet {
                viewDismissalModePublisher.send(shouldDismissView)
            }
        }
    
        func performBusinessLogic() {
            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                self.shouldDismissView = true
            }
        }
    }
    

    和视图对应的是:

    import SwiftUI
    
    struct ContentView: View {
        @State private var isDetailShown = false
        var body: some View {
            VStack {
                Text("Hello, World!")
                Button(action: {
                    self.isDetailShown.toggle()
                }) {
                    Text("Present Detail")
                }
            }
            .sheet(isPresented: $isDetailShown) {
                DetailView()
            }
        }
    }
    
    struct DetailView: View {
        @ObservedObject var viewModel = ViewModel()
        @Environment(\.presentationMode) private var presentationMode
        var body: some View {
            Text("Detail")
            .navigationBarTitle("Detail", displayMode: .inline)
            .onAppear {
                self.viewModel.performBusinessLogic()
            }
            .onReceive(viewModel.viewDismissalModePublisher) { shouldDismiss in
                if shouldDismiss {
                    self.presentationMode.wrappedValue.dismiss()
                }
            }
        }
    }
    

    旧答案:

    关于视图模型中业务逻辑更改的视图关闭的一个非常简单的实现是:

    struct ContentView: View {
        @ObservedObject var viewModel = ViewModel()
        var body: some View {
            Text("Hello, World!")
    
            // the animation() modifier is optional here
            .sheet(isPresented: $viewModel.isSheetShown.animation()) { 
                Text("Sheet Presented")
            }
    
            // From here - for illustration purpose
            .onAppear {
                self.viewModel.perform()
            }
            // To here
    
        }
    }
    
    class ViewModel: ObservableObject {
        @Published var isSheetShown = false
    
        func perform() {
            // this just an example. In real application, you will be responsible to
            // toggle between the states of the `Bool` property
            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                self.isSheetShown.toggle()
                DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                    self.isSheetShown.toggle()
                }
            }
        }
    }
    

    【讨论】:

    • 好吧@theMouk,我想这已经回答了你的问题。如果是这样,您应该首先将其标记为已接受,因为这将帮助未来的读者解决类似问题。而导航视图弹出应该是一个单独的问题。
    • 谢谢!它对我有用(新手)。很多行从 ViewModel 关闭视图。我希望 Swift 的未来版本能够提供更精简的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 2013-07-10
    • 1970-01-01
    相关资源
    最近更新 更多