将 SwiftUI 视图转换为图像时,它无法按预期工作

问题描述 投票:0回答:3

我的目标是将 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()
    }

如有任何帮助,我们将不胜感激。谢谢!

ios swift swiftui uiimage uigraphicsimagerenderer
3个回答
1
投票

与渲染通常的视图并且该视图的大小受设备限制不同,这里不会发生这种情况。因此,您需要将具有定义宽度(可能还有高度)的框架应用于您正在捕获的视图。

当我需要这样做时,我创建了另一个不渲染给用户的视图,并仅将其用于渲染图像。这样,您必须在框架中定义的任何尺寸都不会扰乱用户所看到的内容。

您可能需要一段时间才能做到正确,但请尝试向您正在渲染的视图添加具有所需宽度的框架修改器。 😊


1
投票

下面的代码可以解决您的问题,为了调用 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()
    }
}

输出:


0
投票

你找到解决办法了吗?这让我抓狂

© www.soinside.com 2019 - 2024. All rights reserved.