はじめに
"withAnimation(_:_:)"の挙動を確認したかったので、ポップアップを表示するサンプルを作ってみました。
開発環境
- macOS Big Sur 11.5.1
- Xcode 12.5.1
- Swift 5.4.2
サンプルイメージ
星のアイコンを選択すると、ポップアップが表示され、1秒後に自動で消える。
※ダークモードでビルドしています。
実装
全体の実装
import SwiftUI struct ContentView: View { @State private var selectedRating: Int = 0 private var maximumRating = 5 @State private var isOverlayPresented = false var body: some View { ZStack { HStack(spacing: 25) { ForEach(1 ..< maximumRating + 1) { ratingNumber in Image(systemName: ratingNumber > selectedRating ? "star" : "star.fill") .foregroundColor(ratingNumber > selectedRating ? .gray : .yellow) .onTapGesture { selectedRating = ratingNumber // ポップアップ表示(1秒後に自動で非表示) withAnimation(.easeIn(duration: 0.2)) { isOverlayPresented = true } DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { withAnimation(.easeOut(duration: 0.1)) { isOverlayPresented = false } } } .font(.title) } } if isOverlayPresented { OverlayView(isPresented: $isOverlayPresented) } } } } struct OverlayView: View { @Binding var isPresented: Bool var body: some View { Text("Submitted!") .frame(width: 200, height: 50) .foregroundColor(.black) .background(Color(red: 0.9, green: 0.9, blue: 0.9, opacity: 0.9)) .cornerRadius(10) } }
おまけ
ポップアップを使い回さない場合、以下のようにextentionを使った方が各コンポーネント(ratingViewとoverlayView)における実装の見通しがよくなるのと、どのようにレイアウトしているのかがわかりやすいかも・・・?
import SwiftUI struct ContentView: View { @State private var selectedRating: Int = 0 private var maximumRating = 5 @State private var isOverlayPresented = false var body: some View { ZStack { ratingView if isOverlayPresented { overlayView } } } } private extension ContentView { var ratingView: some View { HStack(spacing: 25) { ForEach(1 ..< maximumRating + 1) { ratingNumber in Image(systemName: ratingNumber > selectedRating ? "star" : "star.fill") .foregroundColor(ratingNumber > selectedRating ? .gray : .yellow) .onTapGesture { selectedRating = ratingNumber // ポップアップ表示(1秒後に自動で非表示) withAnimation(.easeIn(duration: 0.2)) { isOverlayPresented = true } DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { withAnimation(.easeOut(duration: 0.1)) { isOverlayPresented = false } } } .font(.title) } } } } private extension ContentView { var overlayView: some View { Text("Submitted!") .frame(width: 200, height: 50) .foregroundColor(.black) .background(Color(red: 0.9, green: 0.9, blue: 0.9, opacity: 0.9)) .cornerRadius(10) } }
おわりに
今回のケースも含め、アニメーション周りは簡単な動きしか実装経験がないので、実践を通して理解を深めていきたいと思います。
参考
-
https://developer.apple.com/documentation/swiftui/withanimation(_:_:)
-
https://developer.apple.com/documentation/swiftui/animation/easein(duration:)
-
https://developer.apple.com/documentation/swiftui/animation/easeout(duration:)
- Adding a custom star rating component - a free Hacking with iOS: SwiftUI Edition tutorial