从视图模型中关闭视图 [MODAL PAGE]

the*_*ouk 6 swift swiftui combine

我正在使用 swiftUI 并结合,我的 VM 中有一些业务逻辑。有些结果不得不驳斥我的观点。

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

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

self.presentationMode.wrappedValue.dismiss()

Run Code Online (Sandbox Code Playgroud)

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

Moh*_*han 16

如果你想让它变得简单,那么只需在 viewModel 中创建一个名为 goBack 的 Bool 类型的 @Published 变量,并在需要时将其更改为 true,并且在视图中只需使用 .onChange 修饰符(如果该 bool 在更改时为 true),然后运行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()
         }
      }
  }
}
Run Code Online (Sandbox Code Playgroud)


nay*_*yem 15

您不会在SwiftUI. 相反,您通过将.sheet视图绑定到一个布尔属性来使用视图,该布尔属性将从该视图模型中发生变异。

编辑:

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

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

理论讲够了,大家可以看代码,应该不难理解,如下:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和意见同行是:

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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

旧答案:

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

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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)