【问题标题】:Is there a SwiftUI equivalent for viewWillDisappear(_:) or detect when a view is about to be removed?viewWillDisappear(_:) 是否有 SwiftUI 等效项或检测何时将要删除视图?
【发布时间】:2020-05-01 21:08:09
【问题描述】:

在 SwiftUI 中,我试图找到一种方法来检测 视图即将被删除,仅在使用默认 navigationBackButton 时。然后执行一些操作。

使用onDisappear(perform:) 的作用类似于viewDidDisappear(_:),并在另一个视图出现后执行操作。

或者,我认为可以通过检测何时按下默认 navigationBarBackButton 来解决上述问题。但我没有发现任何检测方法。

是否有任何解决方案可以在另一个视图出现之前执行某些操作?

(我已经知道可以通过创建自定义导航返回按钮来关闭视图)

【问题讨论】:

    标签: ios swiftui navigationview


    【解决方案1】:

    这是适合我的方法,它不是纯 SwiftUI,但我认为值得发布

    用法:

       SomeView()
       .onDisappear {
            print("x Default disappear")
        }
       .onWillDisappear { // << order does NOT matter
            print(">>> going to disappear")
        }
    

    代码:

    struct WillDisappearHandler: UIViewControllerRepresentable {
        func makeCoordinator() -> WillDisappearHandler.Coordinator {
            Coordinator(onWillDisappear: onWillDisappear)
        }
    
        let onWillDisappear: () -> Void
    
        func makeUIViewController(context: UIViewControllerRepresentableContext<WillDisappearHandler>) -> UIViewController {
            context.coordinator
        }
    
        func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<WillDisappearHandler>) {
        }
    
        typealias UIViewControllerType = UIViewController
    
        class Coordinator: UIViewController {
            let onWillDisappear: () -> Void
    
            init(onWillDisappear: @escaping () -> Void) {
                self.onWillDisappear = onWillDisappear
                super.init(nibName: nil, bundle: nil)
            }
    
            required init?(coder: NSCoder) {
                fatalError("init(coder:) has not been implemented")
            }
    
            override func viewWillDisappear(_ animated: Bool) {
                super.viewWillDisappear(animated)
                onWillDisappear()
            }
        }
    }
    
    struct WillDisappearModifier: ViewModifier {
        let callback: () -> Void
    
        func body(content: Content) -> some View {
            content
                .background(WillDisappearHandler(onWillDisappear: callback))
        }
    }
    
    extension View {
        func onWillDisappear(_ perform: @escaping () -> Void) -> some View {
            self.modifier(WillDisappearModifier(callback: perform))
        }
    }
    

    【讨论】:

    • onDisappear 在 SwiftUI 中并不总是被调用,但与其他方法相比,这是一个很好的解决方法。
    • onDisappear 在 iOS 13.5 上仍然不可靠 ? 这是一个很好的解决方法。
    • 这是一颗宝石!
    • 这是个好主意。但是,它在 iOS 15 上对我不起作用。在onDisappear 之后,我得到了onWillDisappear。但是,我修改了代码以在 dismantleUIViewController 而不是 viewWillDisappear 中调用回调,并且我得到了正确的时间。
    • 实际上,它对我不起作用。顺序是正确的,但是在视图的生命周期中执行动画似乎为时已晚。
    【解决方案2】:

    您可以将子视图的可见性绑定到某个状态,并监视该状态的变化。

    当子视图被推送时,onChange 块被show == true 调用。弹出子视图时,使用show == false调用相同的块:

    struct ParentView: View {
      @State childViewShown: Bool = false
    
      var body: some View {
        NavigationLink(destination: Text("child view"),
                       isActive: self.$childViewShown) {
          Text("show child view")
        }
        .onChange(of: self.childViewShown) { show in
          if show {
            // child view is appearing
          } else {
            // child view is disappearing
          }
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      您可以像这样触发@Environment .scenePhase 的更改:

      struct YourView: View {
      
          @Environment(\.scenePhase) var scenePhase
      
          var body: Some View {
              VStack {
                 // Your View code
              }
              .onChange(of: scenePhase) { phase in
                 switch phase {
                  case .active:
                      print("active")
                  case .inactive:
                      print("inactive")
                  case .background:
                      print("background")
                  @unknown default:
                      print("?")
                 }
              
              }
      
          }
      }
      

      【讨论】:

      【解决方案4】:

      对于要在屏幕上显示的每个对象,您都有几个操作

      func onDisappear(perform action: (() -> Void)? = nil) -> some View
      //Adds an action to perform when this view disappears.
      
      func onAppear(perform action: (() -> Void)? = nil) -> some View
      //Adds an action to perform when this view appears.
      

      您可以使用类似示例(在此示例中它会影响 VStack):

      
      import SwiftUI
      
      struct TestView: View {
          @State var textObject: String
          var body: some View {
                      VStack {
                       Text(textObject)
                     }
                  .onAppear {
                      textObject = "Vertical stack is appeared"
                  }
                  .onDisappear {
                      textObject = ""
                  }
          }
      }
      
      struct TestView_Previews: PreviewProvider {
          static var previews: some View {
              NavigationView {
                  TestView()
              }
          }
      }
      
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-03
        • 1970-01-01
        • 2019-10-22
        • 2017-04-05
        • 2020-09-22
        相关资源
        最近更新 更多