画面上にメッセージを表示する View。
import SwiftUI
struct Message : View {
var text: String
var body: some View {
HStack ( spacing: 0 ) {
Image ( systemName: "heart.fill" )
. foregroundStyle ( . red)
. font ( . title)
. padding ( )
Text ( text)
. padding ( . trailing, 24 )
}
. clipShape ( . capsule)
. background (
. regularMaterial. shadow ( . drop ( radius: 16 ) ) ,
in : . capsule
)
}
}
#Preview {
Message ( text: "Hello, world!" )
}
どのように、アニメーションやトランジションをつけて、生き生きとした画面にしているか。
Apple 公式サンプルを参考に書いてみます。
Preview 用 View の準備
挙動を何度も確かめるために、
Preview 専用の View を作っておきます。
private struct RefreshPreview : View {
var text: String
@State private var id = false
var body: some View {
Message ( text: text)
. id ( id)
Button ( "Refresh" ) {
id. toggle ( )
}
. buttonStyle ( . borderedProminent)
}
}
【SwiftUI】View の 強制再描画
ボタンを押すと強制的に画面再描画がされて、
表示開始からの動きを確認できるようになります。
まずは アニメーション・トランジションなしでつくる
import SwiftUI
struct Message : View {
var text: String
@State private var showIcon = false
@State private var showText = false
var body: some View {
HStack ( spacing: 0 ) {
if showIcon {
Image ( systemName: "heart.fill" )
. foregroundStyle ( . red)
. font ( . title)
. padding ( )
}
if showText {
Text ( text)
. padding ( . trailing, 24 )
}
}
. clipShape ( . capsule)
. background (
. regularMaterial. shadow ( . drop ( radius: 16 ) ) ,
in : . capsule
)
. frame ( height: 50 )
. onAppear {
Task {
showIcon = true
try await Task . sleep ( for : . seconds ( 1 ) )
showText = true
try await Task . sleep ( for : . seconds ( 1 ) )
showText = false
try await Task . sleep ( for : . seconds ( 1 ) )
showIcon = false
}
}
}
}
private struct RefreshPreview : View {
var text: String
@State private var id = false
var body: some View {
Message ( text: text)
. id ( id)
Button ( "Refresh" ) {
id. toggle ( )
}
. buttonStyle ( . borderedProminent)
}
}
#Preview {
RefreshPreview ( text: "Hello, world !!!" )
. padding ( )
. frame ( maxWidth: . infinity)
}
アイコン画像とテキスト部分をそれぞれの @State で
アイコン表示
↓
テキスト表示
↓
テキスト非表示
↓
アイコン非表示
と Task の中で1秒ごとに変化させています。
しかし、アニメーションやトランジションがないので、
スムーズに View が変化しません。
アニメーション・トランジションをつける
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI
// 【SwiftUI】アニメーションの書き方
// https://zenn.dev/maochanz/articles/b3f2b0dcf949c5
//【SwiftUI】トランジションの書き方
// https://zenn.dev/maochanz/articles/0bcd4bfaa43a0d
struct AnimatedMessage: View {
var text: String
@State private var showIcon = false
@State private var showText = false
var body: some View {
HStack(spacing: 0) {
if showIcon { // *
Image(systemName: "heart.fill")
.foregroundStyle(.red)
.font(.title)
.padding()
.transition(.scale(scale:0.25).combined(with: .opacity)) // *
}
if showText { // *
Text(text)
.padding(.trailing, 24)
.transition(.scale(scale:0.5).combined(with: .opacity)) // *
}
}
.clipShape(.capsule)
.background(
.regularMaterial.shadow(.drop(radius: 16)),
in: .capsule
)
.frame(height: 50)
.onAppear {
Task {
withAnimation(.spring(duration: 0.5, bounce: 0.5)) { // *
showIcon = true
}
try await Task.sleep(for: .seconds(1))
withAnimation { // *
showText = true
}
try await Task.sleep(for: .seconds(3))
withAnimation { // *
showText = false
}
try await Task.sleep(for: .seconds(1))
withAnimation { // *
showIcon = false
}
}
}
}
}
//【SwiftUI】View の 強制再描画
// https://android.benigumo.com/20240324/force-redraw/
private struct RefreshPreview: View {
var text: String
@State private var id = false
var body: some View {
AnimatedMessage(text: text)
.id(id)
Button("Refresh") {
id.toggle()
}
.buttonStyle(.borderedProminent)
}
}
#Preview("once") {
AnimatedMessage(text: "Hello, world !")
.padding()
.frame(maxWidth: .infinity)
}
#Preview("refresh") {
RefreshPreview(text: "Hello, world !!!")
.padding()
.frame(maxWidth: .infinity)
}
まとめ
やっぱ、全然違いますね。
sample-backyard-birds/Multiplatform/Birds/BirdFoodHappinessIndicator.swift at main · apple/sample-backyard-birds
追記: 上記のトランジションっている ?
withAnimation()
記述は必要だとして、
transition()
記述は不要なのではないか。
できるだけシンプルにテンプレート化しておきたいので、
0.25 倍の速度で確認してみます。
上がトランジションなし、
下がトランジションあり。
トランジションはあったほうがいいですね。
やっぱり、Apple 公式サンプルコードは偉大。