コンテンツへスキップ

ImageRendererはUIKitベースのViewをエクスポートできない

SwiftUIのImageRendererは、ListやScrollViewのようなUIKitやAppKitで実装されたビューでサイレントに失敗します。

制限事項

SwiftUIのImageRendererを使うと、任意のSwiftUIビューをUIImageCGImageにレンダリングできます。純粋なSwiftUIビューでは問題なく動作しますが、UIKitやAppKitで実装されたコンポーネントがビューツリーに含まれている場合、サイレントに失敗し、空白または不完全な画像が生成されます。対象となるビューには以下が含まれます:

  • List(UITableView / NSTableViewをラップ)

  • ScrollView(UIScrollView / NSScrollViewをラップ)

  • TextEditor(UITextView / NSTextViewをラップ)

  • Map(MKMapViewをラップ)

コンパイラの警告もランタイムエラーもありません。レンダラーはビュー階層のそれらの部分を単にキャプチャしないだけです。

回避策

リストのようなレイアウトを画像としてエクスポートする必要があった際の解決策は、ListVStackと手動スタイリングで構築した純粋なSwiftUIの同等物に置き換えることでした:

let exportView = VStack(spacing: 0) {
   ForEach(items) { item in
      HStack {
         Text(item.name)
         Spacer()
         Text(item.value)
            .foregroundStyle(.secondary)
      }
      .padding(.horizontal, 16)
      .padding(.vertical, 12)

      if item.id != items.last?.id {
         Divider()
      }
   }
}
.background(.white)
.frame(width: 390)

let renderer = ImageRenderer(content: exportView)
renderer.scale = UIScreen.main.scale

if let image = renderer.uiImage {
   // Use the rendered image
}

VStackForEachによる構成は、UIKitベースのビューに依存することなくListの視覚的な構造を再現します。ディバイダー、パディング、背景を追加することで、エクスポート用途として標準的なリストに十分近い結果が得られます。

実践的なアドバイス

アプリでImageRendererを使用する予定がある場合は、この制約を最初から念頭に置いてエクスポート可能なビューを設計してください。基本的なSwiftUIプリミティブ(スタック、テキスト、シェイプ、イメージ)で構築し、プラットフォーム固有のコントロールをラップしているビューは避けてください。レンダリング出力を早い段階でテストしておくことで、後から空白の領域を発見するフラストレーションを回避できます。

参考になりましたか?BlueskyMastodonでフォローして、Swiftのヒントやインディー開発の最新情報をチェックしてください。