🙌

SwiftUIでマスクの部分をUIImageに変換する

2022/12/03に公開


//
//  ContentView.swift
//

import SwiftUI

struct ContentView: View {

	@State private var captureRect = CGRect.zero
	@State var uiImage: UIImage? = nil

	var body: some View {
		ZStack {
			Image("back")
				.opacity(uiImage == nil ? 1 : 0)

			VStack {
				Group {
					if let uiImage = uiImage {
						Image(uiImage: uiImage)

					} else {
						Rectangle()
							.foregroundColor(.red)
							.frame(width: 200, height: 200)
							.mask {
								mask
							}
					}
				}

				Text("スクショ")
					.foregroundColor(.white)
					.background(Color.black)
					.onTapGesture {
						let scenes = UIApplication.shared.connectedScenes
						let windowScenes = scenes.first as? UIWindowScene
						let rootViewController = windowScenes?.keyWindow?.rootViewController
						self.uiImage = rootViewController?.view!.getImage(rect: captureRect)
					}
			}
		}
	}

	private var mask: some View {
		Rectangle()
			.overlay {
				Rectangle()
					.background(CaptureRect(rect: $captureRect))
					.frame(
						rect: CGRect(x: 50, y: 50, width: 50, height: 50)
					)

					.blendMode(.destinationOut)
			}
	}
}

struct CaptureRect: View {
	@Binding var rect: CGRect

	var body: some View {
		GeometryReader { geometry in
			self.createView(proxy: geometry)
		}
	}

	func createView(proxy: GeometryProxy) -> some View {
		DispatchQueue.main.async {
			self.rect = proxy.frame(in: .global)
		}
		return Rectangle().fill(Color.clear)
	}
}



public extension View {
	/// Position a view using a rectangular frame.
	func frame(rect: CGRect) -> some View {
		return modifier(FrameRectModifier(rect: rect))
	}
}

struct FrameRectModifier: ViewModifier {
	let rect: CGRect
	func body(content: Content) -> some View {
		content
			.frame(width: rect.width, height: rect.height, alignment: .topLeading)
			.position(x: rect.origin.x + rect.width / 2, y: rect.origin.y + rect.height / 2)
	}
}
extension UIView {
	func getImage(rect: CGRect) -> UIImage {
		let renderer = UIGraphicsImageRenderer(bounds: rect)
		return renderer.image { rendererContext in
			layer.render(in: rendererContext.cgContext)
		}
	}
}

Discussion

ログインするとコメントできます