此代码列出了带有刷新图标动画的100行。当使用LazyVStack
而不是VStack
时,向下滚动到此列表的底部后,所有动画都会停止,包括滚动到列表顶部的动画。 VStack
没有此类问题。关于为什么发生这种情况的任何想法,是否有解决方法?
使用Xcode 12.0.1,iOS 14,Swift 5
struct RefreshingList : View {
@State var isAnimating = false
var body: some View {
ScrollView {
LazyVStack { // <- change to VStack to have animations not stop
ForEach(0..<100, id: \.self) { i in
HStack {
Text("\(i) -> ")
self.button()
}
}
}
}
.onAppear {
self.isAnimating=true
}
}
func button() -> some View {
Button(action: {}, label: {
Image(systemName: "arrow.2.circlepath")
.rotationEffect(Angle(degrees: self.isAnimating ? 360.0 : 0.0))
.animation(Animation.linear(duration: 2.0)
.repeatForever(autoreverses: false))
})
}
}
答案 0 :(得分:1)
当观察到屏幕视图发生更改时,就会发生动画。在VStack
中会立即创建所有视图,因此SwiftUI可以观察所有视图的旋转值的变化。
在LazyVStack
情况下,仅根据需要创建视图,因此当.onAppear
中的旋转值更改时,底部的视图不在屏幕上。当它们确实出现在屏幕上时,它的值已经更改,因此不会发生动画。
解决此问题的一种方法是让按钮拥有.isAnimating
@State
变量。然后,只要创建一个,就会进行动画处理。
struct RefreshingList : View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(0..<100, id: \.self) { i in
HStack {
Text("\(i) -> ")
AnimatedButton()
}
}
}
}
}
}
struct AnimatedButton: View {
@State var isAnimating = false
var body: some View {
Button(action: {
}, label: {
Image(systemName: "arrow.2.circlepath")
.rotationEffect(Angle(degrees: self.isAnimating ? 360.0 : 0.0))
.animation(Animation.linear(duration: 2.0)
.repeatForever(autoreverses: false))
})
.onAppear {
isAnimating = true
}
}
}
答案 1 :(得分:0)
struct RefreshingListView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(0..<100) {
LabelView(id: $0)
.id($0)
}
}
.animation(
Animation
.linear(
duration: 2)
.repeatForever(
autoreverses: false))
}
}
}
struct LabelView: View {
@State var
animate = false
var id: Int
var body: some View {
Label(
title: {
Text("<- \(id)")
}, icon: {
Image(
systemName:
"arrow.2.circlepath")
.foregroundColor(.blue)
.padding(.horizontal)
.rotationEffect(
Angle(
degrees:
animate ?
360 : 0))
}
)
.onAppear {
animate
.toggle()
}
}
}