【问题标题】:Convert SwiftUI View to UIImage on iOS 14+在 iOS 14+ 上将 SwiftUI 视图转换为 UIImage
【发布时间】:2021-03-17 15:50:03
【问题描述】:

我可以使用下面的代码将任何 SwiftUI 视图转换为高分辨率的 UIImage。效果很好...直到...我尝试使用大于 CGSize(width: 2730, height: 2730) 的图像尺寸。

如果我将图像尺寸增加到 CGSize(width: 2731, height: 2731) 或更大,则行:

self.drawHierarchy(in: self.layer.bounds, afterScreenUpdates: true)

在“扩展UIView”中,无法再绘制UIImage。

知道为什么会有尺寸限制吗?

注意:我可以通过取消注释“扩展视图”中的 2 行并替换来克服大小限制:

self.drawHierarchy(in: self.layer.bounds, afterScreenUpdates: true)

与:

layer.render(in: context.cgContext)

在“扩展 UIView”... 但是 THEN “layer.render” 不会渲染图像效果,例如“模糊”、SceneKit 子视图或金属。所以使用“self.drawHierarchy”是必须的。

// 1: Set breakpoint on line: print("done") to inspect the high res image
// 2: Run, then tap the image on screen to inspect the highresImage
// 3: repeat after changing the size to CGSize = CGSize(width: 2731, height: 2731)

import SwiftUI

struct ContentView: View {
    @State var blurRadius: CGFloat = 4.0
    let imageSize: CGSize = CGSize(width: 2730, height: 2730)

    var body: some View {
        testView
            .frame(width: 300, height: 300)
            .onTapGesture {
                // Adjust blur radius based on high res image scale
                blurRadius *= imageSize.width * 0.5/300

                // Capture high res image of swiftUI view
                let highresImage = testView.asImage(size: imageSize)
                // set breakpoint here to inspect the high res image size, quality, etc.
                print("done")
                
                // reset blur radius back to 4
                blurRadius = 4
            }
    }

    var testView: some View {
        ZStack {
            Color.blue
            Circle()
                .fill(Color.red)
        }
        .blur(radius: blurRadius)
    }
}

extension UIView {
    func asImage() -> UIImage {
        let format = UIGraphicsImageRendererFormat()
        format.scale = 1
        return UIGraphicsImageRenderer(size: self.layer.frame.size, format: format).image { context in
            self.drawHierarchy(in: self.layer.bounds, afterScreenUpdates: true)
            //layer.render(in: context.cgContext)

        }
    }
}


extension View {
    func asImage(size: CGSize) -> UIImage {
        let controller = UIHostingController(rootView: self)
        controller.view.bounds = CGRect(origin: .zero, size: size)
        //UIApplication.shared.windows.first!.rootViewController?.view.addSubview(controller.view)
        let image = controller.view.asImage()
        //controller.view.removeFromSuperview()
        return image
    }
}

【问题讨论】:

  • 在 iPad Pro(似乎是 2x)上,限制为 4096。同样,如果您使用 8192.0 / UIScreen.main.nativeScaleApple 可能硬编码了 8192x8192 像素限制,您仍然可以在 3x iPhone 上渲染 8192x8192 图像用于渲染视图。

标签: view swiftui uiimage uigraphicsimagerenderer


【解决方案1】:

我不知道为什么,但是在将视图原点的 y 坐标更改为非零值后,它对我有用。这可能是UIHostingController 中的一个错误。

如果你使用很小的Int,你看不出有什么区别,例如:

controller.view.bounds = CGRect(origin: CGPoint(x: 0, y: 0.0001), size: size)

【讨论】:

  • 我刚刚尝试了您的建议,但不行...仍然无法绘制。我正在使用 Xcode 12.2,在 iOS 14.2 iPhone 12 Pro Simulator 上运行。
  • 我对此有一些跟进。看起来我没有正确测试我的解决方案。我实际上可以让它在 1x 和 2x 设备上工作,但由于某种原因它在 3x 设备上失败了。我仍然找不到解决方案,现在将我的视图切换到 UIKit。
猜你喜欢
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多