As the name suggests, IsScrolling provides a ViewModifier to get the current scrolling state of a ScrollView or List in SwiftUI. IsScrolling has good backward and forward compatibility since it is fully implemented natively in SwiftUI. 正如名称所示,IsScrolling 提供了一个 ViewModifier ,用来获取 SwiftUI 中 ScrollView 或 List 当前的滚动状态。由于完全采用了 SwiftUI 原生的方式实现此功能,因此 IsScrolling 具备了很好的前后兼容性。
MIT License
As the name suggests, IsScrolling provides a ViewModifier to get the current scrolling state of a ScrollView or List in SwiftUI. IsScrolling has good backward and forward compatibility since it is fully implemented natively in SwiftUI.
When I was developing SwipeCell two years ago, I needed to close the opened side-swipe menu when the scrollable component (ScrollView, List) started scrolling. This was achieved by injecting a Delegate into the scrollable component via Introspect, and I've been planning to replace this with a more native solution.
IsScrolling has two modes, each based on a different implementation principle:
exclusion
Supports iOS only, no need to add sensors to the views of scrollable component, only one scrollable component in the screen
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
Available for all platforms, monitors multiple scrollable components in the screen at the same time, requires sensor to be added to the views of scrollable component.
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)
}
}
}
For combinations like ScrollView + VStack (HStack), just add one scrollSensor to the scrollable view. For combinations like List, ScrollView + LazyVStack (LazyHStack), you need to add a scrollSensor for each child view.
For details, please check Demo
No matter which monitoring mode IsScrolling provides, it cannot be 100% accurate. After all, IsScrolling inferred the current scrolling state of a scrollable component from certain external phenomena. Known issues are.
.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.