こんにちは。ymurao2です!
「読み込み中...」のような文字列で、末尾の「...」のみアニメーションさせたいときがあると思います。
今回はこちらをご紹介します。
全体像
コードだけ見たい方、お忙しい方のためにまずは全体像です。
struct AnimatedTextView: View {
@State private var dotCount = 0
var dots: String {
String(repeating: ".", count: dotCount)
}
let timer = Timer.publish(every: 0.3, on: .main, in: .common).autoconnect()
var body: some View {
HStack(spacing: 0) {
Text("読み込み中")
.font(.title)
.foregroundStyle(Color.gray)
Text("...")
.font(.title)
.hidden()
.overlay {
Text(dots)
.font(.title)
.foregroundStyle(Color.gray)
.frame(maxWidth: .infinity, alignment: .leading)
.onReceive(timer) { _ in
if dotCount < 3 {
dotCount += 1
} else {
dotCount = 1
}
}
}
}
}
}
おわり
以上です。結構簡単に実装できました!
解説
順を追って解説します。
1. まず「読み込み中...」を用意します
HStackで書くのがミソですね
HStack(spacing: 0) {
Text("読み込み中")
.font(.title)
.foregroundStyle(Color.gray)
Text("...")
.font(.title)
}
2. 「...」を非表示にします
「...」の領域を確保するために.hidden
モディファイアを使用してViewを非表示にします
このとき実際に表示する「...」と大きさを揃えるために.font
で大きさを調整しています
HStack(spacing: 0) {
Text("読み込み中")
.font(.title)
.foregroundStyle(Color.gray)
Text("...")
.font(.title)
+ .hidden()
}
3. .overlay
モディファイアで「...」の上に「...」を表示する
HStack(spacing: 0) {
Text("読み込み中")
.font(.title)
.foregroundStyle(Color.gray)
Text("...")
.font(.title)
.hidden()
+ .overlay {
+ Text("...")
+ .font(.title)
+ .foregroundStyle(Color.gray)
+ }
}
4. アニメーションさせる
0.3秒ごとにアクションを発火させ、dotCount
を増やすことで、いい感じにアニメーションさせています
+ @State private var dotCount = 0
+ var dots: String {
+ String(repeating: ".", count: dotCount)
+ }
// 0.3秒ごとに発火
+ let timer = Timer.publish(every: 0.3, on: .main, in: .common).autoconnect()
var body: some View {
HStack(spacing: 0) {
Text("読み込み中")
.font(.title)
.foregroundStyle(Color.gray)
Text("...")
.font(.title)
.hidden()
.overlay {
Text(dots)
.font(.title)
.foregroundStyle(Color.gray)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ // timerを監視
+ .onReceive(timer) { _ in
+ if dotCount < 3 {
+ dotCount += 1
+ } else {
+ dotCount = 1
+ }
+ }
}
}
}
この記事がお役に立てば、ぜひいいね👍お願いします!