shi*_*shi 21 ios swift swiftui
我使用以下代码作为参考:
我认为它非常接近。似乎可以通过使用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()
}
}
Run Code Online (Sandbox Code Playgroud)
Geo*_*e_E 20
将你的整体包裹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)
}
)
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,您已经存在的scrollViewSize变量是内容的大小,而不是滚动视图的大小。
另请注意,我将 更改==为>=- 这样您就不必完全处于高度,可以在橡皮筋向后滚动的地方过度滚动。
Cou*_*per 16
实现这一目标的一种非常简单的方法如下:
struct ContentView: View {
let array: [String] = (0...100).map { "\($0)" }
let onEndOfList: () -> Void
var body: some View {
List {
ForEach(array, id: \.self) { element in
Text(element)
}
Color.clear
.frame(width: 0, height: 0, alignment: .bottom)
.onAppear {
onEndOfList()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
不用补充,这个基本思想可以增强并应用于 ScrollView 或任何其他可滚动视图。
小智 6
I recently found a somewhat simple method to do this:
ScrollView {
LazyVStack {
ForEach(Array(items.enumerated), id: \.element) { index, i in
Rectangle()
.frame(width: 200, height: 100)
.foregroundColor(.green)
.overlay(Text("\(i)"))
.onAppear {
let isLast = index == items.count
// Do whatever you need checking isLast
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12828 次 |
| 最近记录: |