Resumo:
No SwiftUI, quero animações adequadas quando uma lista de linhas muda de ordem, ao mesmo tempo em que o conteúdo da linha muda de valor. Funciona com List
, não funciona com VStack
/ HStack
. Provavelmente algo a ver com identidade de visualização, transições, animações e transações.
Falha na animação: funciona, mas usa List
:
Tenho uma configuração comum, mas não consigo obter animações perfeitas.
- Uma lista de itens.
- Um dos rótulos em cada linha reflete uma propriedade.
- A lista é classificada por essa propriedade.
- Em uma alteração na propriedade, o rótulo da linha precisa ser animado, mas a ordem geral das linhas também pode mudar e precisar de animação.
No exemplo reproduzível mínimo que estou fornecendo, especificamente temos:
- Uma lista de comentários.
- Um dos rótulos em cada linha reflete a contagem de "votos positivos" para um comentário.
- A lista é classificada por "mais votados".
O problema: Quando tanto o conteúdo quanto a ordem mudam - o rótulo 'se destaca' e 'pula' para a posição final após a animação da linha. O problema é o mesmo, independentemente de ScrollView
ser usado (envolve tudo) ou apenas diretamente um VStack
/ LazyVStack
. O problema é o mesmo, independentemente de LazyVStack
/ VStack
ser usado.
Aqui está um código que você pode colar no ContentView de um novo projeto e observar o problema. Execute no Simulator e use Debug > Slow animations
.
struct ContentView: View {
@State private var comments: [Comment] = []
var body: some View {
HStack {
Text("Sate 1").onTapGesture { comments = [.init("Well done", 6), .init("Interesting", 5), .init("Nice", 4)] }
Text("Sate 2").onTapGesture { comments = [.init("Interesting", 7), .init("Well done", 6), .init("Nice", 4)] }
}
// Option 1: Animation glitch
VStack { ForEach(comments, content: CommentRowView.init(comment:)) }
.padding()
.animation(.default, value: comments)
// Option 2: Works, but uses `List`
// List { ForEach(comments, content: CommentRowView.init(comment:)) }
// .animation(.default, value: comments)
}
}
struct CommentRowView: View {
let comment: Comment
var body: some View {
HStack {
Text(comment.text).font(.largeTitle)
Spacer()
VStack {
Text(comment.upvotes.formatted())
.contentTransition(.numericText())
.animation(.default, value: comment.upvotes)
}
.font(.title)
}.padding().border(.gray)
}
}
struct Comment: Identifiable, Equatable {
var id: String { text }; let text: String; let upvotes: Int
init(_ text: String, _ upvotes: Int) { self.text = text; self.upvotes = upvotes }
}
1 respostas