ども、@kimihom です。
SwiftUI を使ってローディングアイコン(くるくる)を表示させようとした時、まず真っ先に GIF を使おうと思うだろうが、残念ながら GIF サポートは現状ない。何かしらのライブラリを使ったり、自前で動かす実装が必要になる。
ということで、現状の最適な方法としては GIF に代わる自前実装となるのがベストだろう。
参考サイト
まず以下の StackOverflow を参考にさせてもらった。
Activity indicator in SwiftUI - Stack Overflow
ただ、この通りに実装すると最新の iOS 15 だと正しく動作しない部分があったので補足として本記事を記す。
SwiftUI コード
まずは改善版のコードを記しておく。
import Foundation import SwiftUI struct ActivityIndicator: View { @State private var isAnimating: Bool = false var body: some View { GeometryReader { (geometry: GeometryProxy) in ForEach(0..<5) { index in Group { Circle() .frame(width: geometry.size.width / 5, height: geometry.size.height / 5) .scaleEffect(calcScale(index: index)) .offset(y: calcYOffset(geometry)) }.frame(width: geometry.size.width, height: geometry.size.height) .rotationEffect(!self.isAnimating ? .degrees(0) : .degrees(360)) .animation(Animation .timingCurve(0.5, 0.15 + Double(index) / 5, 0.25, 1, duration: 1.5) .repeatForever(autoreverses: false), value: UUID()) } } .aspectRatio(1, contentMode: .fit) .onAppear { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { self.isAnimating = true } } } func calcScale(index: Int) -> CGFloat { return (!isAnimating ? 1 - CGFloat(Float(index)) / 5 : 0.2 + CGFloat(index) / 5) } func calcYOffset(_ geometry: GeometryProxy) -> CGFloat { return geometry.size.width / 10 - geometry.size.height / 2 } } struct ActivityIndicator_Previews: PreviewProvider { static var previews: some View { ActivityIndicator() .frame(width: 200, height: 200) .foregroundColor(.orange) } }
初回ロードがぐちゃぐちゃになる
この StackOverflow のコメントにもあるように、初回ロードでアイコンが左上に向かっていってしまうようなアニメーションとなってしまう。そのため、一時的に処理を待たせる実装で解決している。 asyncAfter
の利用している行が該当するコードだ。
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { self.isAnimating = true }
UUID の指定のない警告
新しい iOS では Animation に UUID の指定が必要のようで、追加する必要があった。
.animation(Animation .timingCurve(0.5, 0.15 + Double(index) / 5, 0.25, 1, duration: 1.5) .repeatForever(autoreverses: false), value: UUID())
終わりに
SwiftUI ではまだ「こんなことやりたい」をさっと解決できるようなものが見つからなかったりする。最初は慣れるまで大変だし、iOS アップデートの度にどんどんと UI の追加がされていく。
その成長を楽しんでいくマインドで、今後も SwiftUI と付き合っていこう。