SwiftUI:关闭模式

时间:2019-07-26 06:03:31

标签: swift swiftui

我知道之前曾有人问过这个问题。不知道这在SwiftUI的Beta 4中是否已更改/取消,但是我似乎无法获得isPresented解决方案来消除sheet所示的模式。

这是我尝试过的简单示例,我认为这可以解决问题,但是单击“关闭”没有任何作用,当我检查self.isPresented?.value时,它就是nil

struct DetailView: View {
    @Environment(\.isPresented) var isPresented: Binding<Bool>?
    var body: some View {
        Button(action: {
            self.isPresented?.value = false
        }) {
            Text("Close")
        }
    }
}

struct ContentView: View {
    @State private var showingModal = false
    var body: some View {
        Button(action: {
            self.showingModal = true
        }) {
            Text("Show detail")
        }.sheet(isPresented: $showingModal) {
            DetailView()
        }
    }
}

根据建议进行更新,此方法有效。似乎我手头上藏着太多书,希望它能得到更新。

struct DetailView: View {
    @Binding var showingModal: Bool
    var body: some View {
        Button(action: {
            self.showingModal = false
        }) {
            Text("Close")
        }
    }
}

struct ContentView: View {
    @State private var showingModal = false
    var body: some View {
        Button(action: {
            self.showingModal = true
        }) {
            Text("Show detail")
        }.sheet(isPresented: $showingModal) {
            DetailView(showingModal: self.$showingModal)
        }
    }
}

4 个答案:

答案 0 :(得分:7)

  

测试版6

使用presentationMode中的@Environment

struct SomeView: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        VStack {
            Text("Ohay!")
            Button("Close") {
                self.presentationMode.wrappedValue.dismiss()
            }
        }
    }
}

答案 1 :(得分:1)

在当前视图中,将State bool设置为false,并将绑定传递到sheet调用中。要显示,请将其设置为true。还要将绑定传递到第二个视图中,以便在那里的按钮可以再次将其设置为false

struct ContentView : View {
    @State var showSheet = false
    var body: some View {
        Button("Show Sheet") {
            self.showSheet.toggle()
        }.sheet(isPresented: self.$showSheet) {
            Modal(isPresented:self.$showSheet)
        }
    }
}

struct Modal : View {
    @Binding var isPresented : Bool
    var body: some View {
        Button("Done", action: {self.isPresented = false})
    }
}

答案 2 :(得分:1)

一个更整洁的解决方案可能是定义一个回调函数:

struct DetailView: View {
    var dismiss: () -> ()

    var body: some View {
        Button(action: dismiss) {
            Text("Close")
        }
    }
}

struct ContentView: View {
    @State private var showingModal = false

    var body: some View {
        Button(action: {
            self.showingModal = true
        }) {
            Text("Show detail")
        }.sheet(isPresented: $showingModal) {
            DetailView(dismiss: { self.showingModal = false })
        }
    }
}

相对于额外簿记的好处在于,DetailView不再需要知道它是一种模式,可以在不同的上下文中使用它。此外,您保留所有用于在原始视图中显示和消除模式的相关代码。

现在,无论使用哪种方法消除模态,您都应该警惕,模态仍然非常容易出错,即使在beta 6中也是如此。在各种情况下,我浪费了太多时间,这些解决方案都无法按需工作:

  • 当您将Button中的ContentView放在List(或ScrollView内时,因为List只是ScrollView的一种特殊类型),则该按钮仅一次起作用。您可以显示模态并关闭它,但是您将无法再次显示它...
  • 使用NavigationView并将Button添加到.navigationBarItems时,您将能够根据需要频繁显示模态。但是,DetailView中的“关闭”按钮将无法工作...

到目前为止,在这些情况下,我无法使关闭按钮正常工作。这极大地限制了现实生活中应用程序中模态的使用。 GM很有可能会解决此问题,但是请注意这些问题,直到已知它们已解决为止。

答案 3 :(得分:1)

另一种解决方案是在您的SwifUI视图中添加一个delegate属性,该属性会将dismiss操作传递回演示者。

protocol MySwiftUIViewDelegate: class {
    func myDismissAction()
}

struct MySwiftUIView {
    weak var delegate: MySwiftUIViewDelegate?
    
    var body: some View {
        Button("Dismiss") {
            self.delegate?.myDismissAction()
        }
    }
}

class MyViewController: UIViewController, MySwiftUIViewDelegate {
    func presentMyView() {
        var myView = MySwiftUIView()
        myView.delegate = self

        let hostingViewController = UIHostingController(rootView: myView)
        present(vc, animated: true, completion: nil)
    }

    // MARK: - MySwiftUIViewDelegate

    func myDismissAction() {
        dismiss(animated: true)
    }
}

虽然这看起来有些令人费解,但最好还是让主持人负责处理撤消,这样视图不必知道它是如何呈现的(例如,push与modal),从而使您代码更具模块化。另外,您可能需要其他委托方法,具体取决于您正在处理的内容,因此您可能已经拥有委托协议。而且,当您关闭视图时,它为您提供了执行任何其他代码的便利位置。

(尽管请记住,根据模式呈现方式/设置的不同,用户可能还可以通过向下拉视图来关闭它。)