进度条在
VStack
中显示动画,但在 List
中不显示动画。 知道为什么吗?
import SwiftUI
struct NoAmimationDemo: View {
@State var progress: Double = 0.0
var body: some View {
VStack {
Button() {
withAnimation {
progress += 20.0
}
} label: { Text("Update") }
// ✅ Animating
ProgressView("", value: progress, total: 100.0)
List {
// ❌ Not animating
ProgressView("", value: progress, total: 100.0)
}
}
}
}
我相信这是一个错误,并且预期的行为是它应该按原样工作。毕竟,如果您将进度视图动画更改为其他内容,例如:
Text("Rotation")
.rotationEffect(Angle(degrees: progress))
然后两个
Text
都可以正确动画。
你也可以做
ProgressView("", value: progress, total: 100.0)
.rotationEffect(Angle(degrees: progress))
看到进度条旋转有动画效果,但“进度”没有动画效果。讽刺!
也就是说,出于某种原因,你可以通过在非工作进度条上添加
.transaction
修饰符来解决这个问题 - 你甚至不需要在闭包中执行任何操作。
ProgressView("", value: progress, total: 100.0)
.transaction { _ in }
即使是一些完全不相关的东西,比如
.badge
,也可以修复它:
ProgressView("", value: progress, total: 100.0)
.badge(0) // the number doesn't seem to matter
似乎有一组特定的修饰符可以修复此行为。我的猜测是,这个集合中的修饰符都在其实现中对
ProgressView
做了一些特定的事情,这就是使进度视图“意识到”当前 Transaction
是动画的原因。
现在我只是在最后加上一个
.transaction { _ in }
,因为除了修复这个问题之外,它没有做任何特别的事情:)
正如其他人提到的,
List
不能很好地处理动画。如果你愿意用 ScrollView + VStack 制作自己的解决方案,我有一个解决方案。
问题是您只设置if内容应该出现,而不是how应该出现。
因此,您只需在每次致电
maxHeight
时设置 isExpanded.toggle
。
struct CustomDisclosureGroup<Label: View, Content: View>: View {
@State private var isExpanded: Bool = false
// 1. Add contentHeight
@State private var contentHeight: CGFloat = .zero
private let label: Label
private let content: Content
init(@ViewBuilder label: () -> Label, @ViewBuilder content: () -> Content) {
self.label = label()
self.content = content()
}
var body: some View {
VStack(spacing: 0) {
Button {
withAnimation {
isExpanded.toggle()
// 2. Set the content height property with a delay so you can observe it
withAnimation(.easeIn.delay(0.01)) {
if isExpanded {
contentHeight = .infinity
} else {
contentHeight = .zero
}
}
}
} label: {
HStack {
label
Spacer()
}
}
if isExpanded {
// 3. Set the height of the content
content
.frame(maxHeight: contentHeight)
}
}
}
}
struct ContentView: View {
@State var items: [Int] = [0, 1, 2, 3]
var body: some View {
// List replaced by ScrollView and VStack
ScrollView {
VStack {
ForEach(items, id: \.self) { item in
CustomDisclosureGroup {
Text(item.formatted())
} content: {
Text("Test text")
Text("Test text")
Text("Test text")
}
}
}
}
}
}