【SwiftUI】スクショできない? なら自作アプリで画面キャプチャを撮るおすすめな方法を教えます | Apple iOS 開発 YouTube セミナー 43


Swift5.1.3 Xcode11.3.1 SwiftUI


- スクリーンショットで画面キャプチャするアプリを自作
- ウェブブラウザの写真を撮る方法を学習
- SwiftUIでSheetにUIImageとしてスクショを表示


スクリーンショットできない?ならアプリを自作して画面保存するやり方を学習しましょう


「以下は動画のハイライトです。」

スクリーンショット禁止のコンテンツを無理やり撮影する行為は法に触れる可能性があります。

本アプリの機能を応用すれば何でも画面キャプチャできるようになりますが、くれぐれも合法の範囲内で撮るようお願いします。

SwiftUIでスクリーンショットを実装するライブラリは現在のところ、私の探した範囲内ではありませんでした。ただ、UIViewをUIImageに変換して保存する機能がありましたため、WebKitとSheetViewを連携させてアプリ内でスクショを可能にするアプリを実装しました。

WebKitの復習は第17回、SheetViewは第21回をご査収ください。本動画ではこれらの実装方法の細かいところは割愛します。

まず、WebViewを以下のように実装してください。


struct WebView : UIViewRepresentable {

var url: URL

func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}

func updateUIView(_ uiView: WKWebView, context: Context) {
let request = URLRequest(url: url)
uiView.load(request)
}

}



URLは以下のプロパティで設定し、引数で指定してViewに表示します。


@State var urlString:String = "https://catch-questions.com/english/"

WebView(url: URL(string: urlString)!)



次にSheetViewを設定します。

uiImageは後でスクリーンショットを格納する変数となりますが、今は無視していただいて結構です。


struct SheetView: View {
@State private var showTrigger = false

@Binding var uiImage: UIImage?

var body: some View {
VStack {
Button("Check Image") {
self.showTrigger = true
}
}.sheet(isPresented: $showTrigger, onDismiss: {
print("Show ScreenShot")
}) {
ScreenShot(uiImage: self.$uiImage)

}
}
}


struct ScreenShot: View {
@Environment(\.presentationMode) var presentation

@Binding var uiImage: UIImage?

var body: some View {
VStack {

if uiImage != nil {
VStack {
Image(uiImage: self.uiImage!)
}
.background(Color.green)
.frame(width: 500, height: 700)
}

Spacer()
Button("Close") {
self.presentation.wrappedValue.dismiss()
}
Spacer()
}.font(.custom("SFProText-Bold", size: 25))
}
}



このSheetViewをContentViewに配置するとボタン仕掛けでSheetを呼ぶActionが実装されます。

VStackで以下のように配置してここまでの動作をビルドして確認してみましょう。


import WebKit

@State var urlString:String = "https://www.apple.com"
@State var uiImage: UIImage? = nil

var body: some View {

VStack {
WebView(url: URL(string: urlString)!)
SheetView(uiImage: $uiImage)

}
}



以上までのコードが無事に動くことが確認で来ましたら、いよいよ本題のスクリーンショットの実装となります。

新しく以下二つのStructとextensionを加えてください。


struct RectSettings: View {
@Binding var rect: CGRect

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

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

extension UIView {
func setImage(rect: CGRect) -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: rect)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}



このStructはRectSettings()はWebViewのウェブブラウザの範囲を入手するためのものです。下のextensionは指定したrect値で表示されているUIViewをUIImageに変換するためのものです。このexensionのfunctionがスクリーンショットとして機能します。

取得したUIImageのデータをuiImageの変数に格納してSheetViewに渡します。

上部のButtonでスクショを撮って、下部のButtonでキャプチャした画面をSheetに表示します。

ビルドして動作確認してみましょう。
本アプリではWebブラウザに表示される画面の写真を保存して後で確認できるようになります。

なお、アプリを閉じてもアプリが落ちない限りはデータほ保持しつづけてくれます。

適宜UIImageをデータ化して保存する処理などは加えていただいても結構です。


ソースコードはYouTubeのコメント欄に記載します。

目次へ戻る

2020年02月03日