web-dev-qa-db-ja.com

SwiftUIビューをUIImageとしてレンダリングする

私はSwiftUIビューをUIImageとしてレンダリングし、ユーザーにカメラロールへの保存を選択するか、電子メールで他のユーザーに送信することを試みています。

例として、50行のリストをUIImageにレンダリングしたいと思います。

_struct MyList: View {
    var body: some View {
        List {
            ForEach(0 ..< 50, id:\.self) {
                Text("row \($0)")
            }
        }
    }
}
_

過去数週間インターネットで検索しましたが、まだうまくいきません。私は2つの異なるアプローチを試しました。

1。 UIHostingControllerここにソース

_let hosting = UIHostingController(rootView: Text("TEST"))
hosting.view.frame = // Calculate the content size here //
let snapshot = hosting.view.snapshot        // output: an empty snapshot of the size
print(hosting.view.subviews.count)          // output: 0
_

私はlayoutSubviews()setNeedsLayout()layoutIfNeeded()loadView()を試してみましたが、すべてのサブビューがまだ0でした。

2。 UIWindow.rootViewControllerここにソース

_var vc = UIApplication.shared.windows[0].rootViewController
vc = vc.visibleController          // loop through the view controller stack to find the top most view controller
let snapshot = vc.view.snapshot    // output: a snapshot of the top most view controller
_

これにより、私が望んでいた出力がほぼ得られます。ただし、取得するスナップショットは文字通りスクリーンショットです。つまり、ナビゲーションバー、タブバー、固定サイズ(画面サイズと同じ)です。キャプチャする必要があるのは、単にバーのないビューのコンテンツであり、画面よりも大きくなることがあります(この例では、私のビューは長いリストです)。

_vc.view.subviews_をクエリして、必要なテーブルビューを検索しようとしましたが、役に立たない[<_TtGC7SwiftUI16PlatformViewHostGVS_42PlatformViewControllerRepresentableAdaptorGVS_16BridgedSplitViewVVS_22_VariadicView_Children7ElementGVS_5GroupGVS_19_ConditionalContentS4_GVS_17_UnaryViewAdaptorVS_9EmptyView______: 0x7fb061cc4770; frame = (0 0; 414 842); anchorPoint = (0, 0); tintColor = UIExtendedSRGBColorSpace 0 0.478431 1 1; layer = <CALayer: 0x600002d8caa0>>]を返しました。

どんな助けでも大歓迎です。

5
Anthony

なぜ人々はあなたの質問が明確ではないと言うのだろうかと思います。それは実際には完全に理にかなっており、私が自分でやろうとしてきたことの1つです。

私はついに、あなたが望むように物事を行う方法を見つけました。複雑ですが、うまくいきます。

アイデアは、2番目の可能性を乱用することです(_UIWindow.rootViewController_)。それはあなたがあなたの窓を取り、あなたが何を描きたいかを理解し、あなたがそれを描くので、それは楽しいです。

しかし問題は、これがメインウィンドウであり、メインウィンドウを描画するように要求することです。

最終的に機能させる方法は、UIViewControllerRepresentableを実行することです。これにより、SwiftUIアプリケーションでUIViewControllerが得られます。次に、その中に単一のUIHostingControllerを配置します。これにより、UIView内にSwiftUIビューが表示されます。つまり、橋を架けます。

update関数で、ディスパッチ非同期をview.layer.render(context)に呼び出して画像を描画できます。

興味深いことに、UIViewControllerRepresentableは実際にはフルスクリーンになります。したがって、.scale(...)を実行して、リスト全体が画面に収まるようにして(renderコマンドはそれが小さくてもかまわない)、中央に配置されるようにします。したがって、画像のサイズが事前にわかっている場合は、HStack { VStack { YourStuff Spacer() } Spacer() }を実行して左上にレンダリングできます。

幸運を!

1
Michel Donais