【Xcode/SwiftUI】親Viewに重ねてViewをフワッと表示させる方法

実装

HomeView.swift (デフォルトだとContentView.swift)

HomeViewのUIは親Viewが重なっていることを分かりやすくするためにテキトーにパーツを多く置いているだけなのでなんでもOKです。

import SwiftUI

struct HomeView: View {
    @State private var username = ""
    @State private var password = ""
    @State private var isFloatingViewVisible = false

    var body: some View {
        ZStack {
            if isFloatingViewVisible {
                FloatingView(dismissAction: {
                    withAnimation {
                        isFloatingViewVisible = false
                    }
                })
                .transition(.asymmetric(insertion: .opacity, removal: .opacity))
                .zIndex(1)
            }
            VStack(spacing: 28) {
                Text("It's fun to learn SwiftUI")
                    .font(.system(size: 24))
                Text("It's fun to learn SwiftUI")
                    .font(.system(size: 24))
                Text("It's fun to learn SwiftUI")
                    .font(.system(size: 24))
                Text("It's fun to learn SwiftUI")
                    .font(.system(size: 24))
                TextField("Username", text: $username)
                    .padding()
                TextField("Password", text: $password)
                    .padding()
                Button {
                    withAnimation {
                        isFloatingViewVisible = true
                    }
                } label: {
                    Text("Show Floating View")
                        .font(.system(size: 24))
                }
                .padding()
                .frame(width: 320, height: 60)
                .background(.orange)
                .foregroundColor(.white)
                Image("<#好きな画像#>")
                    .resizable()
                    .scaledToFill()
                    .frame(width: 120, height: 120)
            }
        }
    }
}

FloatingView.swift (フワッと表示させるView)

import SwiftUI

struct FloatingView: View {
    @State var dismissAction: (() -> Void)

    var body: some View {
        VStack {
            closeButton
            sampleView
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
        .padding(.top, 32)
        .padding(28)
        .background(
            Color.black
                .opacity(0.5)
                .ignoresSafeArea()
        )
        .onTapGesture {
            dismissAction()
        }
    }

    var closeButton: some View {
        HStack {
            Spacer()
            Button(action: dismissAction) {
                Image("<#好きなバツ画像#>")
                    .resizable()
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            .frame(width: 48, height: 48)
            .padding(2)
        }
    }

    var sampleView: some View {
        VStack(spacing: 42) {
            Text("Floating View")
                .font(.system(size: 28))
            Image("<#好きな画像#>")
                .resizable()
                .scaledToFit()
                .padding(.horizontal, 80)
            mainCloseButton
        }
        .padding(20)
        .background(.white)
        .frame(maxWidth: .infinity)
        .cornerRadius(12)
    }

    var mainCloseButton: some View {
        Button(action: {
            dismissAction()
        }, label: {
            Text("Close")
                .font(.system(size: 32))
                .foregroundColor(.white)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        })
        .background(.green)
        .cornerRadius(80)
        .frame(height: 60)
    }
}

struct FloatingView_Previews: PreviewProvider {
    static var previews: some View {
        FloatingView(dismissAction: {})
    }
}