[英]WidgetKit on watchOS with SwiftUI - view with Image(uiImage:) does not render on watchOS
[英]Render SwiftUI View as an 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>>]
[<_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>>]
[<_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>>]
。
任何幫助深表感謝。
這樣的事情對你有用嗎?
import SwiftUI
extension UIView {
func takeScreenshot() -> UIImage {
// Begin context
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
// Draw view in that context
drawHierarchy(in: self.bounds, afterScreenUpdates: true)
// And finally, get image
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if (image != nil) {
UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil);
return image!
}
return UIImage()
}
}
struct ContentView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let someView = UIView(frame: UIScreen.main.bounds)
_ = someView.takeScreenshot()
return someView
}
func updateUIView(_ view: UIView, context: Context) {
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
我想知道為什么人們說你的問題不清楚。 它實際上是完全合理的,這是我一直在尋找自己做的事情之一。
我終於找到了一種按照您希望完成的方式做事的方法,這很復雜,但確實有效。
這個想法是濫用你的第二種可能性( UIWindow.rootViewController
)。 那個很有趣,因為你拿起窗戶,弄清楚你想畫什么,然后畫出來。
但問題是這是您的主窗口,您要求繪制主窗口。
我最終讓它工作的方法是做一個UIViewControllerRepresentable
,它在我的 SwiftUI 應用程序中為我提供了一個UIViewController
。 然后,在它里面,我放了一個UIHostingController
,它在 UIView 中給了我一個 SwiftUI 視圖。 換句話說,我做了一座橋。
在update
函數中,我可以調用異步調度到view.layer.render(context)
來繪制圖像。
有趣的是, UIViewControllerRepresentable
實際上是全屏的。 所以我建議做一個.scale(...)
以便你的整個列表適合屏幕(渲染命令不會介意它變小)並且它會居中。 因此,如果您事先知道圖像的大小,則可以執行HStack { VStack { YourStuff Spacer() } Spacer() }
使其呈現在左上角。
祝你好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.