IsScrolling
September 12, 2022 · View on GitHub
正如名称所示,IsScrolling 提供了一个 ViewModifier ,用来获取 SwiftUI 中 ScrollView 或 List 当前的滚动状态。由于完全采用了 SwiftUI 原生的方式实现此功能,因此 IsScrolling 具备了很好的前后兼容性。
动机
在两年前开发 SwipeCell 的时候,我需要在可滚动组件( ScrollView、List )开始滚动时,关闭已经打开的侧滑菜单。当时是通过 Introspect 为可滚动组件注入了一个 Delegate 才达到此目的,一直打算用更加原生的方式替代此方案。
使用方法
IsScrolling 拥有两种模式,它们分别基于了不同的实现原理:
-
exclusion
仅支持 iOS ,无需为滚动视图添加 sensor ,屏幕中仅能有一个可滚动组件
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")"))
}
}
-
common
适用于全部平台,可同时监控屏幕中的多个可滚动组件,需要为视图添加 sensor
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 是通过某些外在的现象来推断可滚动组件的当前滚动状态。已知的问题有:
- 当滚动内容处于容器的顶部或底部且处于回弹状态时,此时点击停止滚动,再松手,可能会出现滚动状态的扰动( 状态会快速变化一次,此种情况即使使用 UIScrollViewDelegate 也同样存在 )
- 当可滚动组件中的内容出现了非滚动引起的尺寸或位置的变化( 例如 List 中某个视图的尺寸发生了动态变化 ),IsScrolling 在 common 模式下可能会误判断为发生了滚动,但在视图的变化结束后,状态会马上恢复到滚动结束
- 滚动开始后( 状态已变化为滚动中 ),保持手指处于按压状态并停止滑动,common 模式会将此时视为滚动结束,exclusion 模式仍会保持滚动中的状态直到手指结束按压
需求
.iOS(.v14),
.macOS(.v12),
.macCatalyst(.v14),
安装
dependencies: [
.package(url: "https://github.com/fatbobman/IsScrolling.git", from: "1.0.0")
]
版权
This library is released under the MIT license. See LICENSE for details.