SwiftUI 将一个 ScrollView 中的 content 转为 image

news/2024/7/20 20:01:04 标签: swiftui, ios

将一个 ScrollView 中的 content 转为 image

在 iOS 16 / macOS 13 之前,将任何一个 View 转为 image 需要借助 NSHostingControllerUIHostingController 编写相关代码实现,而随着 Apple 在 iOS 16.0 / macOS 13 后发布了新的 API — ImageRenderer 后,仅需一行代码就能将一个 View 转为 image。

下面我们将借助ImageRenderer类将一个 ScrollView 中的 content 转为 image,即使 content 的高度高于屏幕高度,这种方法仍然可将全部的 content 转为 image。

建立一个 ScrollView

假设我们有下面一个 ScrollView:

import SwiftUI

struct ContentView: View {
    let fruits = ["Apple", "Banana", "Cherry"]
    
    var body: some View {
        VStack {
            Text("Fruits")
                .font(.largeTitle)
            
            ScrollView {
								VStack {
		                ForEach(fruits, id: \.self) { fruit in
		                    Text(fruit)
		                }
								}
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

获取 ScrollView 中 content 的 size

在这一步中,我们将 ScrollView 中 content 提取为一个子 View

import SwiftUI

struct ContentView: View {
    let fruits = ["Apple", "Banana", "Cherry"]
    
    var body: some View {
        VStack {
            Text("Fruits")
                .font(.largeTitle)
            
            ScrollView {
                InsideContentView(fruits: fruits)
                    .background(
                        ZStack {
                            GeometryReader {proxy in
                                Color.clear
                                    .onAppear {
                                        print(proxy.size)
                                    }
                            }
                        }
                    )
            }
        }
    }
}

struct InsideContentView: View {
    var fruits: [String]
    var body: some View {
        VStack {
            ForEach(fruits, id: \.self) { fruit in
                Text(fruit)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

将 content 转为 image

import SwiftUI

struct ContentView: View {
    let fruits = ["Apple", "Banana", "Cherry"]
    @State var isTakeSnapshot: Bool = false
    @State var snapshot_proxy: [GeometryProxy] = []
    
    var body: some View {
        VStack {
            Text("Fruits")
                .font(.largeTitle)
            
            ScrollView {
                InsideContentView(fruits: fruits)
                    .background(
                        ZStack {
                            GeometryReader {proxy in
                                Color.clear
                                    .onChange(of: isTakeSnapshot) { _ in
                                        snapshot_proxy = []
                                        snapshot_proxy.append(proxy)
                                    }
                            }
                        }
                    )
            }
            Button("take snapshot", action: {
                isTakeSnapshot.toggle()
                let snapshot_size = snapshot_proxy[0].size
                let content = InsideContentView(fruits: fruits).frame(width: snapshot_size.width)
                let renderer = ImageRenderer(content: content)
                let iamge = renderer.nsImage ?? NSImage()
								// 在这里使用 image, 保存、显示或分享等
            })
        }
    }
}

struct InsideContentView: View {
    var fruits: [String]
    var body: some View {
        VStack {
            ForEach(fruits, id: \.self) { fruit in
                Text(fruit)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Button 中 action 的代码就是我们的实现部分。

有以下几点需要注意的地方:

  • GeometryProxy 不支持初始化,所以我们用一个 GeometryProxy 数组的 State 变量用来存放 content 的 proxy。
  • .frame(width: snapshot_size.width) 保证截图宽度与 content 宽度一致,macOS 上不加 frame 修饰时,截图宽度可能会与 app 窗体宽度不一致。
  • 如果发现截图的分辨率较低,可以加上renderer.scale = 2.0 ,表示将截图分辨率提升 2 倍,详情参加官方文档。

http://www.niftyadmin.cn/n/145008.html

相关文章

前端环境搭建问题报错

1. npm i安装依赖的时候,报错node-sass版本不匹配,错误状态status 1。 node-sass4.12.0 postinstall: node scripts/build.js npm ERR! Exit status 1 Failed at the node-sass4.12.0 postinstall script. npm ERR! This is probably not a problem with…

AidLux AI应用案例悬赏选题 | 带导航功能机器人Demo

AidLux AI 应用案例悬赏征集活动 AidLux AI 应用案例悬赏征集活动是 AidLux 推出的 AI 应用案例项目合作模式,悬赏选题将会持续更新。目前上新的选题涉及泛边缘、机器人、工业检测、车载等领域,内容涵盖智慧零售、智慧社区、智慧交通、智慧农业、智能家…

NetSuite 中国现金流量表功能剖析

作为中国本地化包中的重要组成,现金流量表(CFS)一直处于基本“不可用”的状态。用户抱怨,“报表生成后,出错却不知从而入手”。顾问也是浅尝辄止,改用间接法处理。或者就干脆线下通过银行序时账手工编制了。…

kali配置不同版本java并随时切换

1、安装JDK1.8直接使用下面的地址下载java 1.8:https://repo.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz2、建立目录,将下载的jdk的安装包复制过去并进行解压(root㉿Cwillchris)-[~]# sudo mkdir -p /usr/local/java (root㉿Cwillc…

清华大学学生程序设计竞赛暨高校邀请赛(THUPC)2023 - 初赛(待补题)

心得 看题跟榜比较无力,最终5h4题罚坐 M. 世界杯 输出China即可 K. 众数(前缀和) 最优策略是先取最大的数x,设其出现次数为cnt[x], 然后把小于x的数y每个取min(cnt[y],cnt[x]), 下一轮再取剩下的最大…

防火墙基本信息和规则设置

防火墙是任何系统的组成部分,可用于保护服务器免受来自外部世界的未经身份验证的访问。它有助于防止黑客登录网络上的服务器。防火墙还可用于设置特定规则,以根据 IP 地址限制对系统特定端口的访问。 防火墙的基本功能是监控传入和传出的流量&#xff0c…

五、SALV 添加页眉Top of Page 和页脚End of Page

添加页眉Top of Page 和页脚End of Page 一、页眉和页脚 ​ 可以通过类cl_salv_form_layout_grid ,cl_salv_form_label,cl_salv_form_layout_flow创建,具体方法如下: 创建cl_salv_form_layout_grid ,cl_salv_form_l…

linux 查找符合要求的文档(文件名,大小,类型,权限,时间)

find 命令是一个用于在指定目录下查找文件的强大工具,它可以按照多种条件搜索文件,例如文件名、大小、权限、修改时间等等。下面是一些常用的 find 命令选项和用法: 基本语法: find [path] [expression]其中 path 表示要搜索的目…