はじめに
前回のアニメーションを踏まえて、matchedGeometryEffect()
を使って少し複雑なアニメーションを作っていきます。
目次
matchedGeometryEffect
・つまり、アニメーションを作成の際に、初めの状態と終わりの状態を定義すれば、プログラムが勝手に動いてくれるということです。
・例えば、以下のように楕円は初めに横100縦200として、タップされたら横200縦100に変わっていきました。しかし、変化する最中に横縦は特に指定されていません。
struct ContentView: View {
@State var expand = false
var body: some View {
Ellipse()
.fill(Color.blue)
.frame(width: expand ? 100 : 200, height: expand ? 200 : 100)
.offset(y: expand ? -250 : 0)
.animation(.easeIn)
.onTapGesture {
self.expand.toggle()
}
}
}
・実際に前回作ったカードでmatchedGeometryEffect()
を試していきましょう。
・CourseItem()
は2回呼ばれて、それぞれ初めの状態と終わりの状態を表しています。
isSourse
はビューをグループ内の他のビューのジオメトリのソースとして使用する場合にTrueを指定します。
show.toggle()
はタップされたらBool
が変わります。
struct CoursesView: View {
@State var show = false
@Namespace var namespace
var body: some View {
ZStack {
CourseItem()
.matchedGeometryEffect(
id: "Card", in: namespace, isSource: !show
)
.frame(width: 335, height: 250)
if show {
CourseItem()
.matchedGeometryEffect(id: "Card", in: namespace)
.transition(.opacity)
.zIndex(1)
.edgesIgnoringSafeArea(.all)
}
}
.onTapGesture {
withAnimation(.spring()) {
show.toggle()
}
}
}
}
・この間作ったCourseRow()
を使って、カードがタップされたらCourseRow()
のリストを出せるようにします。
・状態が終わった後にリストを追加するので、2回目に呼ばれたCourseItem()
をScrollView
に突っ込みます。
また、全画面にしたくないので、縦を300にします。
ScrollView {
CourseItem()
.matchedGeometryEffect(id: "Card", in: namespace)
.frame(height: 300)
}
・ForEach
でCourseRow()
を表示されます。
ForEach(0 ..< 20) { item in
CourseRow()
}
まとめ
・気づいているかもしれませんが、リストの消えるタイミングが遅くて、次回はこれを解決します。
ソースコードGithub