我的目标是将 SwiftUI 视图转换为图像。我目前正在为 iOS 15 构建它 这是将视图转换为图像的代码
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)
}
}
}
预期结果:https://share.cleanshot.com/5Pvzb7
实际结果:https://share.cleanshot.com/O4GKUF
下面是具有按钮和图像视图的视图主体
var body: some View {
VStack {
imageView
Spacer(minLength: 200)
Button {
UIImageWriteToSavedPhotosAlbum(imageView.snapshot(), nil, nil, nil)
} label: {
Label("Save to Photos", systemImage: "photo")
}
}
}
Imageview 是用数据硬编码的,图像是从互联网加载的
var imageView: some View {
VStack {
ZStack(alignment: .top) {
Color.red
VStack {
VStack {
HStack(alignment: .top) {
Rectangle.init().frame(width: 56, height: 56).cornerRadius(28)
VStack {
HStack {
Text.init("Yura Filin").font(.system(size: 16))
Spacer()
}.padding(.bottom, 1)
HStack {
Text.init("qweqwewqeqqweqeasd asd asd aosidhsa doaid adoaid adiad hiu uh i hiu ih uhuih iuhiu ih asdi ").lineLimit(90).multilineTextAlignment(.leading).font(.system(size: 16))
Spacer()
}.padding(.bottom, 2)
HStack {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: (286 - 64 - 12))
.onReceive(imageLoader.didChange) { data in
self.image = UIImage(data: data) ?? UIImage() }.cornerRadius(14)
Spacer()
}
Spacer()
}.padding(.leading, 12).readSize { size in
print(size)
}
}
}.padding(16).background(.green).cornerRadius(12)
}.padding(64)
}
}.ignoresSafeArea()
}
如有任何帮助,我们将不胜感激。谢谢!
与渲染通常的视图并且该视图的大小受设备限制不同,这里不会发生这种情况。因此,您需要将具有定义宽度(可能还有高度)的框架应用于您正在捕获的视图。
当我需要这样做时,我创建了另一个不渲染给用户的视图,并仅将其用于渲染图像。这样,您必须在框架中定义的任何尺寸都不会扰乱用户所看到的内容。
您可能需要一段时间才能做到正确,但请尝试向您正在渲染的视图添加具有所需宽度的框架修改器。 😊
下面的代码可以解决您的问题,为了调用 UIImageWriteToSavedPhotosAlbum(),您必须将 NSPhotoLibraryAddUsageDescription 键添加到您的 Info.plist
import SwiftUI
struct ContentView: View {
var imageView: some View {
VStack {
ZStack(alignment: .top) {
Color.red
VStack {
VStack {
HStack(alignment: .top) {
Rectangle.init().frame(width: 56, height: 56).cornerRadius(28)
VStack {
HStack {
Text.init("Yura Filin").font(.system(size: 16))
Spacer()
}.padding(.bottom, 1)
HStack {
Text.init("qweqwewqeqqweqeasd asd asd aosidhsa doaid adoaid adiad hiu uh i hiu ih uhuih iuhiu ih asdi ").lineLimit(90).multilineTextAlignment(.leading).font(.system(size: 16))
Spacer()
}.padding(.bottom, 2)
HStack {
Image("image")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: (286 - 64 - 12))
.cornerRadius(14)
Spacer()
}
Spacer()
}.padding(.leading, 12)
}
}.padding(16).background(.green).cornerRadius(12)
}.padding(64)
}
}.ignoresSafeArea()
}
var body: some View {
VStack {
Button("Save to Photos") {
let image = imageView.snapshot()
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
imageView
Spacer(minLength: 200)
Button("Save to Photos") {
let image = imageView.snapshot()
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
}
}
}
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)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
你找到解决办法了吗?这让我抓狂