Open1
SwiftUI: Form/ListとwithAnimationの相性が悪い件
View
に要素を入れたり抜いたりできますが、その際、withAnimation
を使ってオンオフを切り替えると出し入れの様子をアニメーション化できます。
ただ、これがForm
やList
内だときれいになりません。
import SwiftUI
struct ToggleView: View {
@State var showGlobe: Bool = true
var body: some View {
VStack {
Text("Hello, world!")
if showGlobe {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
}
Button("Toggle") {
withAnimation {
showGlobe.toggle()
}
}
.buttonStyle(.bordered)
}
.padding()
}
}
struct ContentView: View {
var body: some View {
VStack {
ToggleView()
.background(.yellow)
//Form {
List {
ToggleView()
.background(Color(white:0.8))
}
ToggleView()
.background(.green)
ToggleView()
.background(.orange)
}
}
}
#Preview {
ContentView()
}
実際の動きの様子が以下。真ん中のグレー部分がForm
/List
のところです。
上とか下に配置したビューは、表示・非表示の切り替えにともなってスムーズにアニメーションしますが、Form
/List
内に配置したビューは、真ん中を中心にアニメーションしてしまううえにビューの外枠と中身とでアニメーション速度がずれてしまいます。
List
内のビューのサイズ(この場合は高さ)を指定します。
List {
ToggleView()
.background(Color(white:0.8))
.frame(height: 150)
}
こうすると、まだ真ん中を中心にアニメーションしたままですが、外枠の変な動き・ずれがなくなります。
さらに、内側ビュー内のVStack
にSpacer()
を追加したうえ最大高さを指定します。
struct ToggleView: View {
@State var showGlobe: Bool = true
var body: some View {
VStack {
Text("Hello, world!")
if showGlobe {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
}
Button("Toggle") {
withAnimation {
showGlobe.toggle()
}
}
.buttonStyle(.bordered)
Spacer()
}
.padding()
.frame(maxHeight: 130)
}
}
こうすることで、List
外のビューと同じように上部にアンカーがあるような動きにできます。
ただしサイズを適切に指定しないと、やっぱり中心からアニメーションする動きになります。
要素が可変でサイズが決めにくいときはどうするのが良いのかしら。