【SwiftUI】sheetの背景を透過させる方法

2022.09.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

SwiftUIで.sheet.fullScreenCoverでシートを重ねた時に背景を透過させる方法を調べました。

環境

Xcode 14

やりたいこと

やりたいことはこんな風に前面にsheetを出しても背面のViewが見えるようにすることです。

はじめに

今回は、BackViewFrontViewというものを準備しました。

BackView

コード

import SwiftUI

struct BackView: View {
    var body: some View {
        VStack {
            Image("mr-transparent")
                .resizable()
            Text("透けて見えたら成功")
                .bold()
        }
    }
}

プレビュー

FrontView

コード

import SwiftUI

struct FrontView: View {
    var body: some View {

        ZStack {
            RoundedRectangle(cornerRadius: 18)
                .fill(.orange)
                .frame(width: 200, height: 100)
            Text("背面のViewを見たい")
                .bold()
        }
    }
}

プレビュー

背景を透過させる

ZStackでViewを重ねる

ZStackを使用して、Viewを重ねると前面にViewを重ねても背面のViewを確認することが出来ます。

コード

import SwiftUI

struct ZStackLayeredView: View {
    var body: some View {
        ZStack {
            BackView()
            FrontView()
        }
    }
}

プレビュー

sheetを出して前面のViewを透過させる

ZStackで重ねる方法だと背面のViewを確認出来ますが、今回やりたかったことはsheetで前面のViewを透過になります。

コード

import SwiftUI

struct SheetLayeredView: View {
    var body: some View {
        BackView()
            .fullScreenCover(isPresented: .constant(true)) {
                FrontView()
            }
    }
}

プレビュー

単純に重ねるだけだと、sheetの背景が透明になっておらず背面のViewを確認することが出来ませんでした。

.background(clear)にしてもダメ

下記のように.background(.clear)にしてもsheetの背景には影響を与えることはできませんでした。

struct SheetLayeredView: View {
    var body: some View {
        BackView()
            .fullScreenCover(isPresented: .constant(true)) {
                FrontView()
                    .background(.clear)
            }
    }
}

sheetが透過出来ない原因

デフォルトでは全てのHostingControllerの背景が不透明な為、そのViewを見つけて透過させる必要がある

解決策

UIViewRepresentablemakeUIViewの際にPresentationHostingControllerbackgroundColorを透明に変更します。

struct BackgroundClearView: UIViewRepresentable {

    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        Task {
            view.superview?.superview?.backgroundColor = .clear
        }
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {}
}

view.superView?.superViewPresentationHositingControllerの背景のプロパティにアクセスすることが出来ます。そのbackgroundColor.clearを渡して透明にしています。

使い方

今回は先ほどのBackgroundClearView.backgroundに設定するViewのエクステンションを作成しました。

extension View {

    func backgroundClearSheet() -> some View {
        background(BackgroundClearView())
    }
}

完成したもの

無事にsheetの背景を透明にして、背面のViewを確認することが出来ました。

コード

import SwiftUI

struct SheetLayeredView: View {
    var body: some View {
        BackView()
            .fullScreenCover(isPresented: .constant(true)) {
                FrontView()
                    .backgroundClearSheet()
            }
    }
}

プレビュー

おわりに

標準APIで変更できるようになっていない為、ゴニョゴニョしてsheetの背景色を変更する結果になりました。この記事が誰かの救いになれば嬉しいです。

もし、他に良い対応方法があれば教えていただければと思います。

参考