HarmonyOS SnapshotUtil 组件截图完全指南:get() 异步截图 vs getSync() 同步截图
文章目录
- 背景
- 方法总览
- 先准备:给目标组件设置 id
- get():异步截图(推荐)
- getSync():同步截图
- get() 和 getSync() 怎么选?
- 截图预览完整示例
- 常见问题
- 写在最后
背景
近期发现一款很有意思的HarmonyOS 三方库, 地址 @pura/harmony-utils(V1.4.0) , 作者是"桃花镇童长老", 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦
案例demo导航展示
↓↓↓↓↓↓接下来言归正传 ↓↓↓↓
做 HarmonyOS 应用经常会遇到这种需求:截取某个特定组件的图片,比如分享一张卡片、保存用户信息预览图。系统提供了组件截图能力,但 API 用起来有点绕。HoUtils 的SnapshotUtil把这些封装好了,这篇就来讲怎么用。
方法总览
先准备:给目标组件设置 id
组件截图的关键是给目标组件打上 id 标记,截图时通过这个 id 找到对应的组件。
// 被截图的目标组件,必须设置 idColumn({space:8}){Text('这是一个演示组件').fontSize(16).fontColor('#333').fontWeight(FontWeight.Bold)Text('可对该区域进行组件截图').fontSize(13).fontColor('#666')Row({space:8}){ForEach(['红','绿','蓝'],(label:string,idx:number)=>{Column(){Circle({width:40,height:40}).fill(idx===0?'#FF6B6B':idx===1?'#4ECDC4':'#45B7D1')Text(label).fontSize(12).fontColor('#666')}},(label:string)=>label)}}.id('snapshot_target')// 关键:设置组件 id.width('100%').padding(16).backgroundColor('#FFFFFF').borderRadius(10).border({width:2,color:'#4A90E2',style:BorderStyle.Dashed})注意.id('snapshot_target')这一行,这是截图能找到组件的前提。
get():异步截图(推荐)
get()是异步方式,不会阻塞 UI 线程,是推荐的使用方式。
基本用法:
SnapshotUtil.get('snapshot_target').then(pm=>{this.snapshotPixelMap=pm;this.addLog(`get("snapshot_target") → PixelMap${pm.getPixelBytesNumber()}bytes`);}).catch((e:Error)=>{this.addLog(`get() Error:${e.message}`);});返回的是PixelMap对象,可以直接赋给Image组件显示:
if(this.snapshotPixelMap!==undefined){Image(this.snapshotPixelMap).width('100%').height(120).objectFit(ImageFit.Contain).backgroundColor('#F0F0F0').borderRadius(8)}带 options 的用法(缩放截图):
SnapshotUtil.get('snapshot_target',{scale:0.5}).then(pm=>{this.snapshotPixelMap=pm;this.addLog(`get("snapshot_target", {scale:0.5}) →${pm.getPixelBytesNumber()}bytes`);}).catch((e:Error)=>{this.addLog(`get() Error:${e.message}`);});scale: 0.5表示缩放为原始大小的 50%,截出来的图片尺寸更小,文件也更小。
getSync():同步截图
getSync()是同步版本,直接返回PixelMap,用try/catch处理异常:
this.Btn('getSync("snapshot_target")','#16A085',()=>{try{constpm=SnapshotUtil.getSync('snapshot_target');this.snapshotPixelMap=pm;this.addLog(`getSync("snapshot_target") → PixelMap${pm.getPixelBytesNumber()}bytes`);}catch(e){this.addLog(`getSync() Error:${e}`);}})还可以传waitUntilRenderFinished: true,等待渲染完成再截图:
this.Btn('getSync() 带 options (waitUntilRenderFinished=true)','#148F77',()=>{try{constpm=SnapshotUtil.getSync('snapshot_target',{waitUntilRenderFinished:true});this.snapshotPixelMap=pm;this.addLog(`getSync({waitUntilRenderFinished:true}) →${pm.getPixelBytesNumber()}bytes`);}catch(e){this.addLog(`getSync() Error:${e}`);}})waitUntilRenderFinished: true适合那种组件里有动画、异步加载图片等情况,确保内容完全渲染完再截图,避免截到空白。
get() 和 getSync() 怎么选?
| get()(异步) | getSync()(同步) | |
|---|---|---|
| 是否阻塞 UI | 否 | 是(可能短暂卡顿) |
| 错误处理 | .catch() | try/catch |
| 适合场景 | 常规截图,用户点击触发 | 需要立即拿到结果,截图后立刻处理 |
| 推荐程度 | ✅ 首选 | 按需使用 |
截图预览完整示例
import{SnapshotUtil}from'../Utils/SnapshotUtil';import{image}from'@kit.ImageKit';@Entry@Componentstruct SnapshotUtilDemoPage{@StatesnapshotPixelMap:image.PixelMap|undefined=undefined;build(){Column(){// 目标组件Column({space:8}){Text('这是一个演示组件').fontSize(16).fontColor('#333').fontWeight(FontWeight.Bold)Text('可对该区域进行组件截图').fontSize(13).fontColor('#666')Row({space:8}){ForEach(['红','绿','蓝'],(label:string,idx:number)=>{Column(){Circle({width:40,height:40}).fill(idx===0?'#FF6B6B':idx===1?'#4ECDC4':'#45B7D1')Text(label).fontSize(12).fontColor('#666')}},(label:string)=>label)}}.id('snapshot_target').width('100%').padding(16).backgroundColor('#FFFFFF').borderRadius(10)// 截图按钮Button('截取组件').onClick(()=>{SnapshotUtil.get('snapshot_target').then(pm=>{this.snapshotPixelMap=pm;}).catch((e:Error)=>{console.error('截图失败:',e.message);});})// 截图预览if(this.snapshotPixelMap!==undefined){Text('截图预览:').fontSize(13).fontColor('#888')Image(this.snapshotPixelMap).width('100%').height(120).objectFit(ImageFit.Contain).backgroundColor('#F0F0F0').borderRadius(8)}}}}常见问题
Q:截图结果是黑屏或空白?
可能原因:
- 组件还没渲染完成,试试
getSync配合waitUntilRenderFinished: true - 组件 id 写错了,检查
.id()的值和get()传的参数是否一致
Q:截图后怎么保存到相册?
拿到PixelMap之后,可以结合ImageUtil或@ohos.multimedia.image的 packer 打包成 JPEG/PNG 文件,再用photoAccessHelper保存到相册。
写在最后
get()配合PixelMap再渲染成Image组件,基本上覆盖了 90% 的组件截图需求。下一篇聊createFromBuilder——不需要组件在屏幕上,直接离屏渲染并截图。
