前提・実現したいこと
Swift(SwiftUI)で連続したアニメーションを表示したいです。
再生すると、最初は1つの時間間隔で1つのアニメーションが実行されるのですが、後半でアニメーションが実行されないと思えば、次の時間間隔で2つや3つ実行されたりします。
どのように記述すれば1つずつズレなくアニメーションが再生されるか教えていただきたいです。
発生している問題
まず、私が実現したいのは、Imageが上下左右に平行移動したり、回転したり、サイズが変わったりするアニメーションを次々に実行して、Imageを動かすところを見れるようにすることです。
Imageに対するモディファイアは以下の通りです。
Image(systemName: "hare") .font(.system(size: imageSize)) .position(x: self.currentPos.x, y: self.currentPos.y) .rotationEffect(Angle(degrees: deg))
最初にアニメーションをwhile文の中で以下のように順番に実行しようとしたところ、全ての処理が同時に再生されてしまいました。
(playは再生ボタンのオンオフを表すBool、Stepは何番目の処理か(0-index)、Listは上下左右など動きの型を決めた列挙体の配列、Timeは一つのアニメーションにかける時間)
while (play == true && Step < Len) { if List[Step] == .Right { withAnimation(Animation.linear(duration: Time)) { currentPos.x += 80 } } if List[Step] == .Turn { withAnimation(Animation.linear(duration: Time)) { deg += 90 } } if List[Step] == .SizeUp { withAnimation(Animation.linear(duration: Time)) { imageSize += 30 } } Step += 1 }
そこで、次はDispatchQueue.main.asyncAfterを使って、各処理の開始時間を遅らせました。
n番目の処理はTime*nの分遅らせることで、次々に処理していく形です。
while (play == true && Step < Len) { if List[Step] == .Right { DispatchQueue.main.asyncAfter(deadline: .now() + (Time * Double(Step))) { withAnimation(Animation.linear(duration: Time)) { currentPos.x += 80 } } } if List[Step] == .Turn { DispatchQueue.main.asyncAfter(deadline: .now() + (Time * Double(Step))) { withAnimation(Animation.linear(duration: Time)) { deg += 90 } } } if List[Step] == .SizeUp { DispatchQueue.main.asyncAfter(deadline: .now() + (Time* Double(Step))) { withAnimation(Animation.linear(duration: Time)) { imageSize += 30 } } } Step += 1 }
しかしこの形で15~20回目の処理あたりから段々と、1回処理されずに次2回分まとめて動いたり、2回処理されずに次3回分まとめて動いたりしました。
再生間隔よりアニメーション1つにかける時間を短くする、また、アニメーションのdurationを指定せずに再生間隔だけ指定する、どちらの場合でも後半で上記のようなズレが生じました。
どのように記述すれば1つ1つ別々に処理されるのでしょうか。
DispatchQueueについてあまり理解しきれていないせいかもしれませんが、どなたか教えていただけると非常にありがたいです。
あなたの回答
tips
プレビュー