VisibilityTrackingScrollView

这个包提供了一个 ScrollView 的变体,你可以用它来追踪 ScrollView 内部的视图是否真正可见。

用法

    var body: some View {
        VisibilityTrackingScrollView(action: handleVisibilityChanged) {
            LazyVStack {
                ForEach(0..<100, id: \.self) { item in
                    Text("\(item)")
                        .trackVisibility(id: "\(item)")
                }
            }
        }
    }
    
    func handleVisibilityChanged(_ id: String, change: VisibilityChange) {
        switch change {
            case .shown: print("\(id) shown")
            case .hidden: print("\(id) hidden")
        }
    }

任何你想追踪的视图都应该应用 trackVisibility 修饰符。

当被追踪的视图滚动进入或离开容器的可视部分时,回调函数将被调用,并提供被追踪视图的 id 和新的状态。

你可以使用任何可哈希的类型作为传递给 .trackVisibility 的标识符,但它必须与回调函数使用的类型匹配(在上面的例子中,我们使用 String 标识符)。

如果你不小心在两个地方使用了不同的类型,这在编译时不会被检测到,因为它完全是有效的代码。然而,在运行时,trackVisiblity 修饰符将无法找到它期望的环境对象,并且你会得到一个崩溃。

讨论

在理想情况下,这本来是不必要的,因为 ScrollView 本身应该提供对这类功能的良好支持。

这个特殊的视图源于关于 SwiftUI 中不必要的刷新以及如何避免它们的讨论。

类似这样的技术在一个应用程序中使用过,但可能会导致对具有其他用途的环境对象的更改,从而导致更多严格来说不需要的刷新。

我建议尝试隔离这种行为,然后意识到我可能实际上可以将其打包成一个通用的视图/修饰符对。

它大量使用了 GeometryReader,这并不理想,但实际上是我知道的唯一一种能及时工作的方法。

例子

请查看 Extras 文件夹 中的示例项目。