我在SwiftUI中有一个简单的应用程序,显示了一个List
,每个项目都是一个带有两个VStack
元素的Text
:
var body: some View {
List(elements) { item in
NavigationLink(destination: DetailView(item: item)) {
VStack(alignment: .leading) {
Text(item.name)
Text(self.distanceString(for: item.distance))
}
}
}
.animation(.default)
}
.animate()
在其中是因为我想在elements
数组更改时为列表中的更改添加动画。不幸的是,SwiftUI还会对内容进行任何动画处理,从而导致怪异的行为。例如,每个项目中的第二个Text
都非常频繁地更新,并且在更新为新内容之前,更新将立即显示被截断的标签(末尾带有...
)。
那么,当我更新列表的内容时如何防止这种奇怪的行为,而当列表中的元素发生更改时如何保留动画呢?
如果相关,我将创建一个watchOS应用。
答案 0 :(得分:11)
以下应禁用行内部的动画
VStack(alignment: .leading) {
Text(item.name)
Text(self.distanceString(for: item.distance))
}
.animation(nil)
答案 1 :(得分:7)
@Asperi的回答解决了我也遇到的问题(一如既往地支持他的回答)。
我遇到一个问题,我在使用以下内容对整个屏幕进行动画处理:AnyTransition.asymmetric(insertion: .move(edge: .bottom), removal: .move(edge: .top))
所有Text()和Button()子视图也以怪异而不是奇妙的方式进行动画处理。看到Asperi的回答后,我使用animation(nil)解决了这个问题。但是问题是我的按钮在选择时不再带有动画,而我也想要其他动画。
因此,我添加了一个新的State变量来打开和关闭VStack的动画。默认情况下,它们是关闭的,并且在屏幕上对视图进行了动画处理后,我稍加延迟便启用了它们:
struct QuestionView : View {
@State private var allowAnimations : Bool = false
var body : some View {
VStack(alignment: .leading, spacing: 6.0) {
Text("Some Text")
Button(action: {}, label:Text("A Button")
}
.animation(self.allowAnimations ? .default : nil)
.onAppear() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
self.allowAnimations = true
}
}
}
}
只要为与我有类似问题并且需要以Asperi的出色回答为基础的人添加此内容即可。
答案 2 :(得分:1)
感谢@Brett提供延迟解决方案。我的代码在几个地方需要它,因此我将其包装在ViewModifier中。
只需在您的视图中添加 .delayedAnimation()。
您可以传递一秒以外的默认参数和默认动画。
import SwiftUI
struct DelayedAnimation: ViewModifier {
var delay: Double
var animation: Animation
@State private var animating = false
func delayAnimation() {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
self.animating = true
}
}
func body(content: Content) -> some View {
content
.animation(animating ? animation : nil)
.onAppear(perform: delayAnimation)
}
}
extension View {
func delayedAnimation(delay: Double = 1.0, animation: Animation = .default) -> some View {
self.modifier(DelayedAnimation(delay: delay, animation: animation))
}
}
答案 3 :(得分:0)
在我的情况下,上述任何一种都会导致奇怪的行为。解决方案是动画触发元素数组的变化而不是列表。例如:
@State private var sortOrderAscending = true
// Your list of elements with some sorting/filtering that depends on a state
// In this case depends on sortOrderAscending
var elements: [ElementType] {
let sortedElements = Model.elements
if (sortOrderAscending) {
return sortedElements.sorted { $0.name < $1.name }
} else {
return sortedElements.sorted { $0.name > $1.name }
}
}
var body: some View {
// Your button or whatever that triggers the sorting/filtering
// Here is where we use withAnimation
Button("Sort by name") {
withAnimation {
sortOrderAscending.toggle()
}
}
List(elements) { item in
NavigationLink(destination: DetailView(item: item)) {
VStack(alignment: .leading) {
Text(item.name)
}
}
}
}