IsScrolling

中文版说明

顾名思义,IsScrolling 提供了一个 ViewModifier,用于获取 SwiftUI 中 ScrollView 或 List 的当前滚动状态。IsScrolling 具有良好的向后和向前兼容性,因为它完全以 SwiftUI 原生方式实现。

动机

两年前,当我开发 SwipeCell 时,我需要在可滚动组件(ScrollView、List)开始滚动时关闭已打开的侧滑菜单。这是通过使用 Introspect 将 Delegate 注入可滚动组件来实现的,并且我一直计划用更原生化的解决方案来替换它。

用法

IsScrolling 有两种模式,每种模式都基于不同的实现原理

struct VStackExclusionDemo: View {
    @State var isScrolling = false
    var body: some View {
        VStack {
            ScrollView {
                VStack {
                    ForEach(0..<100) { i in
                        CellView(index: i) // no need to add sensor in exclusion mode
                    }
                }
            }
            .scrollStatusMonitor($isScrolling, monitorMode: .exclusion) // add scrollStatusMonitor to get scroll status
        }
    }
}

struct CellView: View {
    @Environment(\.isScrolling) var isScrolling // can get scroll status in scrollable content
    let index: Int
    var body: some View {
        Rectangle()
            .fill(colors[index % colors.count].opacity(0.6))
            .frame(maxWidth: .infinity, minHeight: 80)
            .overlay(Text("ID: \(index) Scrolling: \(isScrolling ? "T" : "F")"))
    }
}
struct ListCommonDemo: View {
    @State var isScrolling = false
    var body: some View {
        VStack {
            List {
                ForEach(0..<100) { i in
                    CellView(index: i)
                        .scrollSensor() // Need to add sensor for each subview
                }
            }
            .scrollStatusMonitor($isScrolling, monitorMode: .common)
        }
    }
}

对于 ScrollView + VStack (HStack) 这样的组合,只需向可滚动视图添加一个 scrollSensor。对于 List, ScrollView + LazyVStack (LazyHStack) 这样的组合,您需要为每个子视图添加一个 scrollSensor。

详情请查看 Demo

局限性和缺点

无论 IsScrolling 提供哪种监控模式,它都不能 100% 准确。毕竟,IsScrolling 是从某些外部现象推断出可滚动组件的当前滚动状态。已知问题如下。

要求

.iOS(.v14),

.macOS(.v12),

.macCatalyst(.v14),

安装

dependencies: [
  .package(url: "https://github.com/fatbobman/IsScrolling.git", from: "1.0.0")
]

许可

本库基于 MIT 许可发布。详情请查看 LICENSE