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

sg24os4d  于 2023-02-25  发布在  Swift
关注(0)|答案(3)|浏览(360)

我有一个如下的视图。我想知道它是否是屏幕上显示的视图。有什么功能可以实现这个功能吗?

struct TestView: View {
    var body: some View {
        Text("Test View")
    }
}
lf3rwulv

lf3rwulv1#

您可以在符合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.")
        }
    }
}

PS:虽然这个解决方案涵盖了大多数情况,但它有许多边缘情况没有涵盖。当苹果发布更好的解决方案时,我会更新这个答案。

5lwkijsr

5lwkijsr2#

可以使用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
            }
k5hmc34c

k5hmc34c3#

正如Oleg所提到的,根据您的用例,onAppear的一个可能问题是,只要View在视图层次结构中,它的action就会被执行,而不管该视图是否对用户可能可见。
我的用例是在视图实际可见时延迟加载内容,我不想依赖于封装在LazyHStack或类似文件中的视图。
为了实现这一点,我在View中添加了一个扩展onBecomingVisible,它具有与onAppear相同的API,但仅当视图first与屏幕的可见边界相交时才调用该操作,之后不会调用该操作。

public extension View {
    
    func onBecomingVisible(perform action: @escaping () -> Void) -> some View {
        modifier(BecomingVisible(action: action))
    }
}

private struct BecomingVisible: ViewModifier {
    
    @State var action: (() -> Void)?

    func body(content: Content) -> some View {
        content.overlay {
            GeometryReader { proxy in
                Color.clear
                    .preference(
                        key: VisibleKey.self,
                        // See discussion!
                        value: UIScreen.main.bounds.intersects(proxy.frame(in: .global))
                    )
                    .onPreferenceChange(VisibleKey.self) { isVisible in
                        guard isVisible, let action else { return }
                        action()
                        action = nil
                    }
            }
        }
    }

    struct VisibleKey: PreferenceKey {
        static var defaultValue: Bool = false
        static func reduce(value: inout Bool, nextValue: () -> Bool) { }
    }
}

讨论
我对在代码中使用UIScreen.main.bounds并不感到兴奋!也许可以使用几何代理来代替,或者使用一些@Environment值--尽管我还没有考虑过这个问题。

相关问题