Swift・iOS

Swiftを中心に学んだことを記録に残すブログです。技術に関係ない記事もたまに書いています。

【SwiftUI】ポップアップ(オーバーレイ)を表示する

 

はじめに

"withAnimation(_:_:)"の挙動を確認したかったので、ポップアップを表示するサンプルを作ってみました。

 

開発環境

 

サンプルイメージ

星のアイコンを選択すると、ポップアップが表示され、1秒後に自動で消える。

※ダークモードでビルドしています。

f:id:hfoasi8fje3:20210812204744g:plain

 

実装

全体の実装

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)
    }
}

 

おわりに

今回のケースも含め、アニメーション周りは簡単な動きしか実装経験がないので、実践を通して理解を深めていきたいと思います。

 

参考