web-dev-qa-db-ja.com

SwiftUI:コンテンツの変更をアニメーション化せずにリストで変更をアニメーション化

SwiftUIにListを表示するシンプルなアプリがあり、各項目は2つの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)
}
_

elements配列が変更されたときにリストへの変更をアニメーション化したいので、.animate()がそこにあります。残念ながら、SwiftUIはコンテンツへの変更もアニメーション化し、奇妙な動作を引き起こします。たとえば、各アイテムの2番目のTextは非常に頻繁に更新されます。更新では、新しいコンテンツに更新する前に、ラベルが切り捨てられます(最後に_..._を使用)。

では、リストのコンテンツを更新するときにこの奇妙な動作を防ぎ、リストの要素が変更されてもアニメーションを維持するにはどうすればよいですか?

必要に応じて、watchOSアプリを作成しています。

2
BlackWolf

以下は、行の内部のアニメーションを無効にする必要があります

VStack(alignment: .leading) {
    Text(item.name) 
    Text(self.distanceString(for: item.distance))
}
.animation(nil)
7
Asperi

@Asperiの回答により、私が抱えていた問題も修正されました(いつものように彼の回答に賛成しました)。

以下を使用して画面全体をアニメーション化するときに問題が発生しました:AnyTransition.asymmetric(insertion: .move(Edge: .bottom), removal: .move(Edge: .top))

また、すべてのText()およびButton()サブビューも、奇妙であまり素晴らしい方法ではなくアニメーション化されます。 Asperiの答えを見た後、私はanimation(nil)を使用して問題を修正しました。ただし、問題は、ボタンが選択時にアニメーション化されなくなり、他の必要なアニメーションもアニメーション化されなくなったことです。

そこで、新しい状態変数を追加して、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の優れた答えに基づいて構築する必要があるすべての人にこれを追加します。

0
Brett