「SwiftUIで6角形を作りたい。」の内容をふまえると、UIImageView のエクステンションを SwiftUI と統合したいというより、画像を六角形でくりぬくのが目的なのでしょうか?
画像に対して .clipShape()
を使い、好きな形のシェイプをわたせばその形にくりぬくことができます。前述の質問で作った Hexagon
シェイプがあるなら、次のようにして正六角形にくりぬけます。
swift
1struct ContentView: View {
2 var body: some View {
3 Image("Sample")
4 .resizable()
5 .aspectRatio(contentMode: .fill)
6 .clipShape(Hexagon())
7 }
8}
これが、ブラー効果を画像にかけながらその効果を正六角形でくりぬきたいとなると少し難しくなります。SwiftUI ではブラー効果自体は .blur
でかんたんにかけられますが、その効果範囲だけをシェイプでくりぬくことができません。
swift
1struct ContentView: View {
2 var body: some View {
3 Image("Sample")
4 .resizable()
5 .aspectRatio(contentMode: .fill)
6 .blur(radius: 5, opaque: true)
7 // .clipShape(Hexagon()) を追加してもブラーのかかった画像全体をくりぬいてしまう
8 }
9}
ZStack
を使ってブラーのかかった画像とくりぬいた画像を重ねるのも一つの手ですが、スマートではないです。
swift
1struct ContentView: View {
2 var body: some View {
3 ZStack {
4 Image("Sample")
5 .resizable()
6 .aspectRatio(contentMode: .fill)
7 .blur(radius: 50, opaque: true)
8
9 Image("Sample")
10 .resizable()
11 .aspectRatio(contentMode: .fill)
12 .clipShape(Hexagon())
13 }
14 }
15}
そこで、UIKit に用意された効果そのもののビュー UIVisualEffectView
を SwiftUI に統合し、そのビューをくりぬくようにします。
UIKit のビューを SwiftUI で使うには UIViewRepresentable
プロトコルを使って構造体を作ります。
基本的には makeUIView()
メソッドで UIKit のビューを作って返し、updateUIView
で状態を更新します。いちばんかんたんな作り方としては、そのクラス特有のプロパティの値だけ仲介してセットするようにすればいいです。
よく分からなければ今はコピペでもかまいません。
swift
1struct VisualEffectView<T: UIVisualEffectView>: UIViewRepresentable {
2 var effect: UIVisualEffect?
3 func makeUIView(context: UIViewRepresentableContext<Self>) -> T {
4 T()
5 }
6 func updateUIView(_ uiView: T, context: UIViewRepresentableContext<Self>) {
7 uiView.effect = effect
8 }
9}
これで VisualEffectView
というビューが SwiftUI で使えます。これを使って、画像の上にブラー効果を重ね、それをうまくくりぬいて真ん中だけ効果がかからないようにします。
全体としては次のようになります。
swift
1import SwiftUI
2import UIKit
3
4struct ContentView: View {
5 var body: some View {
6 ZStack {
7 Image("Sample")
8 .resizable()
9 .aspectRatio(contentMode: .fill)
10
11 VisualEffectView(effect: UIBlurEffect(style: .regular))
12 .mask(
13 ZStack(alignment: .center) {
14 Color.white
15 Hexagon().foregroundColor(.black)
16 }
17 .compositingGroup()
18 .luminanceToAlpha()
19 )
20 }
21 }
22}
23
24struct VisualEffectView<T: UIVisualEffectView>: UIViewRepresentable {
25 var effect: UIVisualEffect?
26 func makeUIView(context: UIViewRepresentableContext<Self>) -> T {
27 T()
28 }
29 func updateUIView(_ uiView: T, context: UIViewRepresentableContext<Self>) {
30 uiView.effect = effect
31 }
32}
ここからは興味があれば読むくらいでかまいませんが、以下のコードの役割はそれぞれこのようなになります。
swift
1.mask(
2 ZStack(alignment: .center) {
3 Color.white // 全体を覆う白いビュー
4 Hexagon().foregroundColor(.black) // 正六角形の黒いシェイプ
5 }
6 .compositingGroup() // ZStack の中身をひとつのレイヤととらえて合成するためにグループ化
7 .luminanceToAlpha() // 黒い部分を透明に、白い部分を不透明にする
8)
.luminanceToAlpha()
という黒い部分ほど透明にする効果を使うために、全体を覆うビューとシェイプで白黒画像を作っています。