Geo*_*e_E 8 uiimage ios swift swiftui ios15
我尝试UIImage使用 HWS 中的代码从 SwiftUI 视图创建快照:如何将 SwiftUI 视图转换为图像。
我得到以下结果,这显然是不正确的,因为图像被截断了。
代码:
struct ContentView: View {
@State private var savedImage: UIImage?
var textView: some View {
Text("Hello, SwiftUI")
.padding()
.background(Color.blue)
.foregroundColor(.white)
.clipShape(Capsule())
}
var body: some View {
ZStack {
VStack(spacing: 100) {
textView
Button("Save to image") {
savedImage = textView.snapshot()
}
}
if let savedImage = savedImage {
Image(uiImage: savedImage)
.border(Color.red)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
extension View {
func snapshot() -> UIImage {
let controller = UIHostingController(rootView: self)
let view = controller.view
let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}
Run Code Online (Sandbox Code Playgroud)
看起来作为快照的原始视图比应有的位置要低,但我不确定。我该如何解决?
我们发现这个问题不会出现在 iOS 14 上,只会出现在 iOS 15 上。所以问题是……如何在 iOS 15 上解决这个问题?
小智 24
我最近也注意到这个问题。我在不同的模拟器(例如 iPhone 8 和 iPhone 13 Pro)上进行了测试,并意识到偏移量似乎始终是状态栏高度的一半。所以我怀疑当你调用 时drawHierarchy(in:afterScreenUpdates:),内部 SwiftUI 总是考虑安全区域插入。
因此,我使用视图修饰符修改了扩展snapshot()中的函数,并且它起作用了:ViewedgesIgnoringSafeArea(_:)
extension View {
func snapshot() -> UIImage {
let controller = UIHostingController(rootView: self.edgesIgnoringSafeArea(.all))
let view = controller.view
let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
避免额外空白所需的主要事情是额外的安全区域插入应该减去原始的安全区域插入
这是我当前的实现,可渲染不在屏幕上的视图。使用运行 iOS 16.2 Beta 的 iPhone 7、iOS 15.7 和 iPhone 13 以及运行 iOS 16.2 Beta 的 iPad mini 6 进行测试。
extension View {
func asImage() -> UIImage {
let controller = UIHostingController(rootView: self.edgesIgnoringSafeArea(.all))
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
window?.rootViewController?.view.addSubview(controller.view)
controller.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1)
controller.additionalSafeAreaInsets = UIEdgeInsets(top: -controller.view.safeAreaInsets.top, left: -controller.view.safeAreaInsets.left, bottom: -controller.view.safeAreaInsets.bottom, right: -controller.view.safeAreaInsets.right)
let targetSize = controller.view.intrinsicContentSize
controller.view.bounds = CGRect(origin: .zero, size: targetSize)
controller.view.sizeToFit()
let image = controller.view.asImage()
controller.view.removeFromSuperview()
return image
}
}
extension UIView {
func asImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4366 次 |
| 最近记录: |