ios - 如何检测用户何时到达 ScrollView 的底部?
问题描述
我使用以下代码作为参考:
我认为它非常接近。似乎可以通过使用origin.maxY
代替来解决origin.y
,但origin.maxY
似乎没有提供GeometryReader
(严格来说:)CGRect
。
如何检测用户何时到达 ScrollView 的底部?
import SwiftUI
struct ContentView: View {
let spaceName = "scroll"
@State var scrollViewSize: CGSize = .zero
var body: some View {
ScrollView {
ChildSizeReader(size: $scrollViewSize) {
VStack {
ForEach(0..<100) { i in
Text("\(i)")
}
}
.background(
GeometryReader { proxy in
Color.clear.preference(
key: ViewOffsetKey.self,
value: -1 * proxy.frame(in: .named(spaceName)).origin.y
)
}
)
.onPreferenceChange(
ViewOffsetKey.self,
perform: { value in
print("offset: \(value)") // offset: 1270.3333333333333 when User has reached the bottom
print("height: \(scrollViewSize.height)") // height: 2033.3333333333333
if value == scrollViewSize.height {
print("User has reached the bottom of the ScrollView.")
} else {
print("not reached.")
}
}
)
}
}
.coordinateSpace(name: spaceName)
.onChange(
of: scrollViewSize,
perform: { value in
print(value)
}
)
}
}
struct ViewOffsetKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
struct ChildSizeReader<Content: View>: View {
@Binding var size: CGSize
let content: () -> Content
var body: some View {
ZStack {
content().background(
GeometryReader { proxy in
Color.clear.preference(
key: SizePreferenceKey.self,
value: proxy.size
)
}
)
}
.onPreferenceChange(SizePreferenceKey.self) { preferences in
self.size = preferences
}
}
}
struct SizePreferenceKey: PreferenceKey {
typealias Value = CGSize
static var defaultValue: Value = .zero
static func reduce(value _: inout Value, nextValue: () -> Value) {
_ = nextValue()
}
}
解决方案
把你的整体包裹ScrollView
在你的 中,这样你就可以得到它本身ChildSizeReader
的高度。ScrollView
因为偏移量从顶部开始为零,所以在滚动视图的底部时,结束点不在屏幕顶部,而是在底部。这个差异就是滚动视图的高度。这意味着ScrollView
从 offset 开始0
并转到total content height - scroll view height
。
代码:
struct ContentView: View {
let spaceName = "scroll"
@State var wholeSize: CGSize = .zero
@State var scrollViewSize: CGSize = .zero
var body: some View {
ChildSizeReader(size: $wholeSize) {
ScrollView {
ChildSizeReader(size: $scrollViewSize) {
VStack {
ForEach(0..<100) { i in
Text("\(i)")
}
}
.background(
GeometryReader { proxy in
Color.clear.preference(
key: ViewOffsetKey.self,
value: -1 * proxy.frame(in: .named(spaceName)).origin.y
)
}
)
.onPreferenceChange(
ViewOffsetKey.self,
perform: { value in
print("offset: \(value)") // offset: 1270.3333333333333 when User has reached the bottom
print("height: \(scrollViewSize.height)") // height: 2033.3333333333333
if value >= scrollViewSize.height - wholeSize.height {
print("User has reached the bottom of the ScrollView.")
} else {
print("not reached.")
}
}
)
}
}
.coordinateSpace(name: spaceName)
}
.onChange(
of: scrollViewSize,
perform: { value in
print(value)
}
)
}
}
请注意,您已经存在的scrollViewSize
变量是内容的大小,而不是滚动视图的大小。
另请注意,我将其更改==
为>=
- 这样您就不必完全处于高度,可以在橡皮筋向后滚动的地方过度滚动。
推荐阅读
- json - 颤振未处理的异常:类型'_InternalLinkedHashMap
JSON 请求 - excel - VBA调用奇怪的行为
- python - 使用带有布尔值的 argparse.subparser
- java - 使用 hasNext() Scanner 方法只允许一组 X 输入
- reactjs - 反应:过滤搜索/“城市”未定义 no-undef
- r - 整洁或未嵌套的 S4 BF BayesFactor 对象
- angular - 使用 Windows 身份验证时 SignalR 客户端 CORS 错误
- javascript - 将表中的选定行保存在本地存储中
- visual-studio - 如何为我的 c++ 程序修复这个 Visual Studio 错误?
- scala - 在 IntelliJ 中导入库 sbt