SwiftUIで.sheet
や.fullScreenCover
でシートを重ねた時に背景を透過させる方法を調べました。
環境
Xcode 14
やりたいこと
やりたいことはこんな風に前面にsheetを出しても背面のViewが見えるようにすることです。
はじめに
今回は、BackView
とFrontView
というものを準備しました。
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を見つけて透過させる必要がある
解決策
UIViewRepresentable
でmakeUIView
の際にPresentationHostingController
のbackgroundColor
を透明に変更します。
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?.superView
でPresentationHositingController
の背景のプロパティにアクセスすることが出来ます。その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の背景色を変更する結果になりました。この記事が誰かの救いになれば嬉しいです。
もし、他に良い対応方法があれば教えていただければと思います。