我有一个LazyVStack,有很多行。代码:
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(0 ..< 100) { i in
Text("Item: \(i + 1)")
.onAppear {
print("Appeared:", i + 1)
}
}
}
}
}
}最初屏幕上只有大约40行可见,而77行则触发了onAppear。为什么是这个,为什么它在屏幕上可见之前就被调用了?我不明白为什么SwiftUI必须“预加载”它们。
是否有办法解决这个问题,或者如果这是有意的,我如何才能准确地知道最后一个可见项(接受不同的行高)?
编辑
文档 for LazyVStack声明:
堆栈是“懒惰”的,因为堆栈视图在需要在屏幕上呈现项之前不会创建项。
那这一定是个虫子吧,我猜?
发布于 2021-11-28 22:46:40
用文档的话来说,onAppear不该是这样的:
堆栈是“懒惰”的,因为堆栈视图在需要在屏幕上呈现项之前不会创建项。
但是,如果您在使它正常工作时遇到了问题,请参阅下面的解决方案。
虽然我不知道为什么onAppear的行会被提前触发,但我已经创建了一个解决方案。它读取滚动视图边界的几何形状和单个视图来跟踪、比较它们,并设置它是否可见。
在本例中,当上一项的顶部边缘在滚动视图的边界中可见时,isVisible属性将发生更改。这可能不是当它在屏幕上可见时,由于安全区域,但您可以将此更改为您的需要。
代码:
struct ContentView: View {
@State private var isVisible = false
var body: some View {
GeometryReader { geo in
ScrollView {
LazyVStack {
ForEach(0 ..< 100) { i in
Text("Item: \(i + 1)")
.background(tracker(index: i))
}
}
}
.onPreferenceChange(TrackerKey.self) { edge in
let isVisible = edge < geo.frame(in: .global).maxY
if isVisible != self.isVisible {
self.isVisible = isVisible
print("Now visible:", isVisible ? "yes" : "no")
}
}
}
}
@ViewBuilder private func tracker(index: Int) -> some View {
if index == 99 {
GeometryReader { geo in
Color.clear.preference(
key: TrackerKey.self,
value: geo.frame(in: .global).minY
)
}
}
}
}struct TrackerKey: PreferenceKey {
static let defaultValue: CGFloat = .greatestFiniteMagnitude
static func reduce(value: inout Value, nextValue: () -> Value) {
value = nextValue()
}
}发布于 2021-11-28 23:30:24

根据我上面的评论,这是可行的。
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(0 ..< 100) { i in
Text("Item: \(i + 1)")
.id(i)
.frame(width: 100, height: 100)
.padding()
.onAppear { print("Appeared:", i + 1) }
}
}
}
}
}发布于 2022-11-14 14:07:00
这似乎令人难以置信,但是仅仅添加一个包含GeometryReader的ScrollView就可以解决这个问题。
GeometryReader { _ in
ScrollView(.vertical, showsIndicators: false) {
LazyVStack(spacing: 14) {
Text("Items")
LazyVStack(spacing: 16) {
ForEach(viewModel.data, id: \.id) { data in
MediaRowView(data: data)
.onAppear {
print(data.title, "item appeared")
}
}
if viewModel.state == .loading {
ProgressView()
}
}
}
.padding(.horizontal, 16)
}
}https://stackoverflow.com/questions/70147827
复制相似问题