iOS16+で登場したSwiftUIの新機能「ImageRenderer」によって、SwftUIビューを画像としてレンダリング(※1)し、取得することができるようになりました。
本記事では、ImageRendererの使い方、具体的な実装例について見ていきます。
(※1) レンダリング
あるデータを処理または演算することで、画像や映像を表示させること。
[ 本記事はこんな人におすすめ ]
・SwiftUIのビューを画像として取得したい(UIImage, CGImage)
・SwiftUIでアプリ開発をしている
「ImageRenderer」はiOS16+で登場したSwiftUIのビューから画像を作成することができるオブジェクトを指します。
ユーザーの操作によって、オンデマンド(※2)形式でSwiftUIビューを画像として生成し、取得することができます。
下記の実装サンプルは、ImageRendererを用いてビューを画像取得する実装例の一つです。
トロフィー画像とテキストが混合した複合ビューの全体を、レンダラーを使ってUIImageとして生成し、シートに渡しています。
こちらの実装については、後述の【ImageRendererの具体的な実装例】で詳しく紹介しています。
(※2)オンデマンド
ユーザーがリクエストしたタイミングでサービスが提供される方式のこと。
ブラウザなどを通じてユーザのリクエストに応じて、テキストや画像などのコンテンツを配信しているインターネット上の多くのデータ配信は、オンデマンド方式といえる。
SwiftUIビューを画像データとして取得する基本的なコードを見ていきます。
① ImageRenderer(content:)
に、画像として取得したいビューを渡して、レンダラーを初期化します。
② ①で初期化したレンダラーから、.uiImageメソッドを用いてUIImageを取り出します。.cgImageメソッドも用意されており、CGImageを取得することも可能です。
/// ImageRendererを使って画像を取得するコード
@State var renderedImage: UIImage? // レンダリング画像を格納
// ❶ImageRenderer(content:)にビューを渡して初期化
let renderer = ImageRenderer(content: HogeView())
// ❷UIImageを取り出す
if let image = renderer.uiImage { // .cgImageもある
renderedImage = image
}
上記のコードでは、ビューをUIImageとして取得しています。CGImageとして取得するメソッドも用意されているので、用途によって使い分けてください。
上記のコードを全体として見ると、例えば以下のようになります。
/// ImageRendererを使って画像を取得する基本コード
struct BasicImageRenderer: View {
@State private var renderedImage: UIImage? // レンダリング画像を格納
var body: some View {
VStack {
Button("SwiftUIビューを画像として取得") {
// ImageRenderer(content:)にビューを渡す
let renderer = ImageRenderer(content: HogeView())
if let image = renderer.uiImage { // .cgImageもある
renderedImage = image
}
}
}
}
/// ImageRendererによって画像化されるビュー
private func HogeView() -> some View {
VStack {
// 何らかのView...
}
}
}
ボタンアクション内にビューのレンダリング処理を設定しています。レンダリングに成功すれば、UIImageが取得できます。
本記事では、レンダリング対象のビューをプライベートメソッドとして定義していますが、独自のカスタムビュー構造体(struct)のレンダリングももちろん可能です。
Image
出力には、テキスト、画像、図形、およびこれらのタイプの複合ビューなど、SwiftUI がレンダリングするビューのみが含まれます。
Web ビュー、メディア プレーヤー、一部のコントロールなど、ネイティブ プラットフォーム フレームワーク (AppKit および UIKit) によって提供されるビューはレンダリングされません。
最後に、Appleのドキュメントで紹介されている実装をもとに、ImageRendererのより具体的な使用例を見ていきましょう。
今回の実装では、複数のビューによって構築された複合ビューを、ImageRendererを用いて一つのUIImageとして生成していきます。
以下は、本実装の完成図です。
「ユーザーのアチーブメント(功績)を表現したビュー」を、ボタンアクション内で初期化したレンダラーに渡して画像生成し、シートビューに渡すという処理の流れです。
レンダラーによる画像生成に関わるコードを抜粋すると、以下のようになります。
// レンダリング画像を格納するプロパティ
@State private var renderedImage: UIImage?
// アチーブメントビューの初期化
let trophyAndDate = CreateAwardView(forUser: playerName, date: achievementDate)
Button("アチーブメントを保存") {
let renderer = ImageRenderer(content: trophyAndDate) // ⬅︎画像生成したいビューを渡す
if let image = renderer.uiImage {
renderedImage = image
}
}
アチーブメントビュー単体のコードは以下です。
本実装ではビューメソッドとして定義していますが、もちろんView構造体でもOKです。
こちらの複合ビューをレンダラーに渡すことで、一つのUIImgeデータとして生成していきます。
では、実装コードの全体像を見ていきましょう。
・トロフィー画像、ユーザー名、日時が設定されたアチーブメントビューを、レンダラーによってUIImageとして取得します。
・【アチーブメントを保存】ボタンのアクションによって、ImageRenderer(content:)にアチーブメントビューが渡され、ビューのレンダリングが実行されます。
・onChangeによってUIImageの取得成功が確認できれば、シートの遷移が発火し、シートビューに取得画像が渡されます。
// ImageRendererを用いた具体的なビューの画像取得実装例
import SwiftUI
struct AchievementRendererView: View {
let playerName = "CodeCandy"
let achievementDate = Date.now
@State private var renderedImage: UIImage? // レンダリング画像を格納
@State private var showSheet: Bool = false // 保存完了を知らせるシートを管理
var body: some View {
// アチーブメントビューの初期化
let trophyAndDate = CreateAwardView(forUser: playerName,
date: achievementDate)
VStack {
trophyAndDate
Button("アチーブメントを保存") {
let renderer = ImageRenderer(content: trophyAndDate)
if let image = renderer.uiImage {
renderedImage = image
// 用途によって、外部データベースへの保存処理など...
}
}
.padding()
.onChange(of: renderedImage) { _ in
if renderedImage != nil {
showSheet.toggle()
}
}
}
.sheet(isPresented: $showSheet) {
SavedAchievementView(image: renderedImage)
}
}
/// ImageRendererによって画像化されるアチーブメントビュー
private func CreateAwardView(forUser: String, date: Date) -> some View {
VStack {
Image(systemName: "trophy")
.resizable()
.frame(width: 200, height: 200)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.shadow(color: .mint, radius: 5)
Text(playerName)
.font(.largeTitle)
Text(achievementDate.formatted())
}
.multilineTextAlignment(.center)
.frame(width: 200, height: 290)
}
}
/// アチーブメントの保存が完了を知らせるシートビュー
struct SavedAchievementView: View {
// レンダリング取得したUIImage画像を親ビューから受け取る
var image: UIImage?
var body: some View {
VStack(spacing: 30) {
Text("アチーブメント保存完了!")
.font(.title2)
if let image {
Image(uiImage: image)
}
}
}
}
親ビュー側のプライベートメソッドとして定義されているアチーブメントビューが、レンダラーによってUIImageとして生成されて、シート側に渡せていることがわかりますね。
こちらの実装例では、取得したUIImageデータを単にシートに渡して表示しているだけですが、用途によってローカルや外部データベースへの画像保存処理を挟むことになるかと思います。
以上、iOS16+のSwiftUI新機能「ImageRenderer」についてでした!
要点をまとめておきます。
・ImageRenderer(content:)にSwiftUIビューを渡して、画像を取得する
・UIImageに加え、CGImageとしての取得も可能
・SwiftUI がレンダリングできるビューのみが出力できる(テキスト、画像、図形など)
ImageRendererを使うことによって、より直感的にSwiftUIビューの画像化と取得が実装できるようになりました!
iOS16+サポートでアプリを開発している方はぜひ活用してみていただければと思います。
本記事が参考になれば幸いです。
本記事のソースコード
\ SHARE /
アプリ開発が学べる勉強会を開催中!
CodeCandyではアプリ開発を学ぶための勉強会を定期開催しています。
学習する習慣を身につけたい、他の参加者と作業したい、アプリ開発の基本をマスターしたい、という方のために無料で学べる勉強会です。
グループにメンバー登録して頂くと、イベント開催時にメールで通知されます。
徹底した基礎学習からマスターするiPhoneアプリ開発集中オンライン講座開講!
本書「iPhoneアプリ開発集中講座」を執筆している現役エンジニア講師陣が直接に指導!
基礎、課題実習で実践力を鍛えて、オリジナルアプリ公開までチャレンジ!
充実した転職支援もあるので、エンジニアへ転職したい人にもおすすめです!
まずは、現役エンジニアに相談できる無料相談をご利用ください。
2022年2月よりSwift学習を始め、4月からiOSアプリ開発オンラインスクール「CodeCandy」にてアプリ開発を学ぶ。 2023年10月に個人開発アプリ「unico」をリリース。現在はアプリの機能アップデートをしながら、スクール運営の技術ブログの執筆や、出版書籍の入稿チェック・デバッグにも携わる。