【问题标题】:SwiftUI: close modalSwiftUI:关闭模式
【发布时间】:2019-07-26 06:03:31
【问题描述】:

我知道以前有人问过这个问题并回答过。不确定这是否在 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)
        }
    }
}

【问题讨论】:

  • 是的,beta 4 似乎打破了这一点。请在此处查看我的答案(靠近底部),了解如何设置关闭按钮)。 stackoverflow.com/questions/57148220/…
  • “对我来说,记账似乎太多了”所有这些真理来源的言辞都非常漂亮,但是对于像dismiss 这样的命令,还是有话要说的。

标签: swift swiftui


【解决方案1】:

测试版 6

使用@Environment 中的presentationMode

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

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

【讨论】:

  • 有没有办法从 ViewModel 调用它? (ObservableObject
  • 更新: self.presentationMode.wrappedValue.dismiss() 现在用于 Beta 6
  • @ThibautMottet 刚刚更新了答案。感谢您的评论。 (Apple 终于发布了 Xcode Beta 6,嗯?耶!)
【解决方案2】:

在呈现视图中,将 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})
    }
}

【讨论】:

    【解决方案3】:

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

    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 解决,但请注意这些问题,直到它们被修复为止。

    【讨论】:

      【解决方案4】:

      另一种解决方案是将delegate 属性添加到您的 SwifUI 视图中,它将关闭操作传回给演示者。

      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)
          }
      }
      

      虽然这看起来有点令人费解,但也可以说让演示者负责处理解雇更好,这样视图就不必知道它是如何呈现的(例如推送与模态),从而使您的代码更加模块化。另外,您可能需要其他委托方法,具体取决于您正在处理的内容,因此您可能已经有了委托协议。当视图被关闭时,它为您提供了一个方便的地方来执行任何额外的代码。

      (尽管请记住,根据模态演示样式/设置,用户也可以通过下拉视图来关闭。)

      【讨论】:

        猜你喜欢
        • 2019-10-24
        • 2021-06-04
        • 2020-02-06
        • 1970-01-01
        • 1970-01-01
        • 2020-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多