SwiftUI:视图完全移除时的ViewModifier回调,类似于onDisappear,但只调用一次

g52tjvyc  于 2024-01-05  发布在  Swift
关注(0)|答案(1)|浏览(123)

当视图是层次结构的一部分时,onAppearonDisappear修饰符可以被多次调用。
我知道有一个技巧,使一个onLoad ViewModifier像这样

extension View {
    func onLoad(perform action: (() -> Void)? = nil) -> some View {
        self.modifier(ViewDidLoadModifier(action: action))
    }
}

struct ViewDidLoadModifier: ViewModifier {
    @State private var viewDidLoad = false
    let action: (() -> Void)?

    func body(content: Content) -> some View {
        content
            .onAppear {
                if viewDidLoad == false {
                    viewDidLoad = true
                    action?()
                }
            }
    }
}

字符串
从上面的代码中,onLoad只会被调用一次

struct MyView: View {
    var body: some View {
        Text("Hello View")
            .onAppear {
                // may print multiple times
                print("onAppear")
            }
            .onLoad {
               // only prints once
               // when the view first appears in the hierarchy
               print("onLoad")
            }
    }
}


有没有一种方法可以有一个onUnLoad ViewModifier?

struct MyView: View {
    var body: some View {
        Text("Hello View")
            .onDisappear {
                // may print multiple times
                print("onDisappear")
            }
            .onUnLoad {
               // only prints once,
               // when the view is completely removed
               print("onUnLoad")
            }
    }
}

iklwldmw

iklwldmw1#

我找到了一种方法来创建onUnload ViewModifier,将UIView Package 在UIViewRepresentable中,并使用其willMove(toSuperview:)事件

struct ViewDidUnloadModifier: ViewModifier {
    let action: () -> Void

    func body(content: Content) -> some View {
        ZStack {
            ViewDidUnloadRepresentable(action: action)
            content
        }

    }
}

struct ViewDidUnloadRepresentable: UIViewRepresentable {
    let action: () -> Void

    func makeUIView(context: Context) -> DidUnloadView {
        return DidUnloadView(action: action)
    }

    func updateUIView(_ uiView: DidUnloadView, context: Context) {
    }
}

final class DidUnloadView: UIView {

    let action: () -> Void

    init(action: @escaping () -> Void) {
        self.action = action
        super.init(frame: .zero)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func willMove(toSuperview newSuperview: UIView?) {
        if newSuperview == nil {
            action()
        }
        super.willMove(toSuperview: newSuperview)
    }

}

字符串
在UIKit中,如果调用了视图的willMove(toSuperview:)方法,并且toSuperview为nil,则意味着将从层次结构中完全删除UIView。

struct MyView: View {
    var body: some View {
        Text("Hello View")
            .onDisappear {
                // may print multiple times
                print("onDisappear")
            }
            .onUnload {
               // only prints once when removed, EUREKA!
               print("onUnload")
            }
    }
}

相关问题