如何检查视图是否显示在屏幕上?(Swift 5 和 SwiftUI)

cod*_*o11 11 xcode ios swift swift5 swiftui

我有一个像下面这样的观点。我想知道它是否是屏幕上显示的视图。有没有实现这个的功能?

struct TestView: View {
    var body: some View {
        Text("Test View")
    }
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*ohn 20

正如Oleg 所提到的,根据您的用例,一个可能的问题onAppear是,action只要它View位于视图层次结构中,它就会立即执行,无论视图是否对用户可能可见。

\n

我的用例是希望在视图实际可见时延迟加载内容。我不想依赖封装在 aLazyHStack或类似的视图中。

\n

为了实现这一点,我添加了一个扩展,它具有onBecomingVisibleView相同类型的 API onAppear,但仅在(且仅当)视图首次与屏幕的可见边界相交时才调用该操作。该操作随后不会被调用。

\n
public extension View {\n    \n    func onBecomingVisible(perform action: @escaping () -> Void) -> some View {\n        modifier(BecomingVisible(action: action))\n    }\n}\n\nprivate struct BecomingVisible: ViewModifier {\n    \n    @State var action: (() -> Void)?\n\n    func body(content: Content) -> some View {\n        content.overlay {\n            GeometryReader { proxy in\n                Color.clear\n                    .preference(\n                        key: VisibleKey.self,\n                        // See discussion!\n                        value: UIScreen.main.bounds.intersects(proxy.frame(in: .global))\n                    )\n                    .onPreferenceChange(VisibleKey.self) { isVisible in\n                        guard isVisible, let action else { return }\n                        action()\n                        action = nil\n                    }\n            }\n        }\n    }\n\n    struct VisibleKey: PreferenceKey {\n        static var defaultValue: Bool = false\n        static func reduce(value: inout Bool, nextValue: () -> Bool) { }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

讨论

\n

UIScreen.main.bounds我对在代码中使用并不感到兴奋!也许可以使用几何代理来代替,或者使用一些@Environment值 \xe2\x80\x93 我还没有考虑过这一点。

\n


Bib*_*cob 10

您可以在任何符合 View 协议的视图上使用 onAppear。

struct TestView: View {
    @State var isViewDisplayed = false
    var body: some View {
        Text("Test View")
        .onAppear {
            self.isViewDisplayed = true
        }
        .onDisappear {
            self.isViewDisplayed = false
        }
    }

    func someFunction() {
        if isViewDisplayed {
            print("View is displayed.")
        } else {
            print("View is not displayed.")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这并不是真正显示在屏幕上的。即使它没有显示在屏幕上也会被调用。只需加载视图,它就会调用 `.onAppear()` (9认同)
  • 这不是一个很好的解决方案。如果发生全屏覆盖并且底层视图消失,则 onDisappear 将不会触发。 (2认同)
  • 当视图变得可见时,不保证调用 OnAppear。 (2认同)

Ses*_*udi 8

您可以使用 GeometryReader 和 GeometryProxy 在全局范围内检查视图的位置。

        struct CustomButton: View {
            var body: some View {
                GeometryReader { geometry in
                    VStack {
                        Button(action: {
                        }) {
                            Text("Custom Button")
                                .font(.body)
                                .fontWeight(.bold)
                                .foregroundColor(Color.white)
                        }
                        .background(Color.blue)
                    }.navigationBarItems(trailing: self.isButtonHidden(geometry) ?
                            HStack {
                                Button(action: {
                                }) {
                                    Text("Custom Button")
                                } : nil)
                }
            }

            private func isButtonHidden(_ geometry: GeometryProxy) -> Bool {
    // Alternatively, you can also check for geometry.frame(in:.global).origin.y if you know the button height.
                if geometry.frame(in: .global).maxY <= 0 {
                    return true
                }
                return false
            }
Run Code Online (Sandbox Code Playgroud)