news 2026/7/5 13:55:55

《图片添加贴纸》四、PhotoViewPicker使用指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《图片添加贴纸》四、PhotoViewPicker使用指南

HarmonyOS PhotoViewPicker(图片选择器)使用指南

效果

一、概述

在HarmonyOS应用开发中,经常需要从用户相册中选择图片或视频。PhotoViewPickerphotoAccessHelper模块提供的系统级图片选择器,具有以下优势:

  • 无需申请权限:PhotoViewPicker采用安全控件模式,不需要声明READ_IMAGEVIDEO权限。
  • 系统级UI:调用后弹出系统相册选择界面,用户体验统一且流畅。
  • 灵活配置:支持选择图片、视频或混合类型,可设置最大选择数量。
  • 安全隔离:返回的URI仅对当前应用有效,不会暴露相册的其他内容。

官方文档参考:PhotoViewPicker - HarmonyOS开发者文档


二、模块导入

import{photoAccessHelper}from'@kit.MediaLibraryKit';

三、API详解

3.1 PhotoViewPicker类

classPhotoViewPicker{select(photoSelectOptions:PhotoSelectOptions):Promise<PhotoSelectResult>}

PhotoSelectOptions 配置项:

属性类型说明
MIMETypePhotoViewMIMETypes媒体文件类型过滤
maxSelectNumbernumber最大可选择数量
photoPickerInfosPhotoPickerInfo[]预选中的资源信息
preselectedModePreselectedMode预选模式

PhotoViewMIMETypes 枚举值:

枚举值说明
PhotoViewMIMETypes.IMAGE_TYPE仅显示图片
PhotoViewMIMETypes.VIDEO_TYPE仅显示视频
PhotoViewMIMETypes.IMAGE_VIDEO_TYPE显示图片和视频

PhotoSelectResult 返回值:

属性类型说明
photoUrisstring[]选中资源的URI数组
isMaxNumberReachedboolean是否达到最大选择数量

3.2 创建实例

letpicker=newphotoAccessHelper.PhotoViewPicker();

四、基础使用示例

4.1 选择单张图片

import{photoAccessHelper}from'@kit.MediaLibraryKit';import{image}from'@kit.ImageKit';import{fileIo}from'@kit.CoreFileKit';@Entry@Componentstruct PickSingleImageDemo{@StateselectedImage:image.PixelMap|undefined=undefined;asyncpickImage():Promise<void>{try{// 1. 创建选择器实例letpicker=newphotoAccessHelper.PhotoViewPicker();// 2. 配置选择选项letoptions=newphotoAccessHelper.PhotoSelectOptions();options.MIMEType=photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;options.maxSelectNumber=1;// 3. 调起系统选择器letresult=awaitpicker.select(options);// 4. 获取选中的图片URIif(result.photoUris.length>0){leturi=result.photoUris[0];// 5. 读取图片数据并创建PixelMapletfile=fileIo.openSync(uri);letstat=fileIo.statSync(file.fd);letbuffer=newArrayBuffer(stat.size);fileIo.readSync(file.fd,buffer);fileIo.closeSync(file.fd);letimageSource=image.createImageSource(buffer);this.selectedImage=awaitimageSource.createPixelMap();}}catch(err){console.error('选择图片失败: '+(errasError).message);}}build(){Column({space:20}){if(this.selectedImage){Image(this.selectedImage).width(280).height(280).objectFit(ImageFit.Cover).borderRadius(12)}else{Column().width(280).height(280).borderRadius(12).border({width:2,color:'#BDBDBD',style:BorderStyle.Dashed}).justifyContent(FlexAlign.Center).children([Text('+').fontSize(48).fontColor('#BDBDBD')])}Button('从相册选择').width(200).height(44).fontSize(16).fontColor(Color.White).backgroundColor('#0A59F7').borderRadius(22).onClick(()=>this.pickImage())}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}

4.2 选择多张图片

@Entry@Componentstruct PickMultipleImagesDemo{@StateselectedImages:image.PixelMap[]=[];asyncpickMultipleImages():Promise<void>{try{letpicker=newphotoAccessHelper.PhotoViewPicker();letoptions=newphotoAccessHelper.PhotoSelectOptions();options.MIMEType=photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;options.maxSelectNumber=9;// 最多选择9张letresult=awaitpicker.select(options);// 遍历所有选中的图片letpixelMaps:image.PixelMap[]=[];for(leturiofresult.photoUris){letfile=fileIo.openSync(uri);letstat=fileIo.statSync(file.fd);letbuffer=newArrayBuffer(stat.size);fileIo.readSync(file.fd,buffer);fileIo.closeSync(file.fd);letimageSource=image.createImageSource(buffer);letpixelMap=awaitimageSource.createPixelMap();pixelMaps.push(pixelMap);}this.selectedImages=pixelMaps;}catch(err){console.error('选择图片失败: '+(errasError).message);}}build(){Column({space:16}){// 网格展示选中的图片Grid(){ForEach(this.selectedImages,(item:image.PixelMap,index:number)=>{GridItem(){Image(item).width('100%').height('100%').objectFit(ImageFit.Cover).borderRadius(8)}},(item:image.PixelMap,index:number)=>index.toString())}.columnsTemplate('1fr 1fr 1fr').rowsGap(8).columnsGap(8).width('90%').height(320)Button(`选择图片 (${this.selectedImages.length}/9)`).onClick(()=>this.pickMultipleImages())}.width('100%').height('100%').padding({top:40})}}

五、进阶用法

5.1 读取图片为PixelMap的工具函数

在实际项目中,建议将图片读取逻辑封装为工具函数:

import{image}from'@kit.ImageKit';import{fileIo}from'@kit.CoreFileKit';import{photoAccessHelper}from'@kit.MediaLibraryKit';/** * 通过URI读取图片并创建PixelMap * @param uri 图片文件URI * @returns PixelMap对象 */exportasyncfunctioncreatePixelMapFromUri(uri:string):Promise<image.PixelMap>{letfile=fileIo.openSync(uri);letstat=fileIo.statSync(file.fd);letbuffer=newArrayBuffer(stat.size);fileIo.readSync(file.fd,buffer);fileIo.closeSync(file.fd);letimageSource=image.createImageSource(buffer);letpixelMap=awaitimageSource.createPixelMap({editable:true// 设置为可编辑,便于后续处理});returnpixelMap;}/** * 使用PhotoViewPicker从相册选择图片 * @param maxCount 最大选择数量 * @returns 选中的PixelMap数组 */exportasyncfunctionpickImagesFromGallery(maxCount:number=1):Promise<image.PixelMap[]>{letpicker=newphotoAccessHelper.PhotoViewPicker();letoptions=newphotoAccessHelper.PhotoSelectOptions();options.MIMEType=photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;options.maxSelectNumber=maxCount;letresult=awaitpicker.select(options);letpixelMaps:image.PixelMap[]=[];for(leturiofresult.photoUris){letpixelMap=awaitcreatePixelMapFromUri(uri);pixelMaps.push(pixelMap);}returnpixelMaps;}

5.2 结合Image组件直接展示

如果不需要PixelMap,可以直接使用URI展示图片(性能更好):

@Entry@Componentstruct DirectURIDisplayDemo{@StateimageUri:string='';build(){Column({space:20}){if(this.imageUri){// 直接使用URI展示图片,无需创建PixelMapImage(this.imageUri).width(280).height(280).objectFit(ImageFit.Cover).borderRadius(12)}Button('选择图片').onClick(async()=>{letpicker=newphotoAccessHelper.PhotoViewPicker();letoptions=newphotoAccessHelper.PhotoSelectOptions();options.MIMEType=photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;options.maxSelectNumber=1;letresult=awaitpicker.select(options);if(result.photoUris.length>0){this.imageUri=result.photoUris[0];}})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}

5.3 在图片编辑器中替换背景图

@Entry@Componentstruct ReplaceBackgroundDemo{@StatebgImage:image.PixelMap|undefined=undefined;asyncreplaceBackground():Promise<void>{try{letpicker=newphotoAccessHelper.PhotoViewPicker();letoptions=newphotoAccessHelper.PhotoSelectOptions();options.MIMEType=photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;options.maxSelectNumber=1;letresult=awaitpicker.select(options);if(result.photoUris.length>0){letfile=fileIo.openSync(result.photoUris[0]);letstat=fileIo.statSync(file.fd);letbuffer=newArrayBuffer(stat.size);fileIo.readSync(file.fd,buffer);fileIo.closeSync(file.fd);letimageSource=image.createImageSource(buffer);// 释放旧的PixelMapif(this.bgImage){this.bgImage.release();}this.bgImage=awaitimageSource.createPixelMap({editable:true});}}catch(err){console.error('替换背景失败: '+(errasError).message);}}build(){Stack(){// 背景图Image(this.bgImage??$r('app.media.background')).width(300).height(300).objectFit(ImageFit.Cover).borderRadius(12)// 替换按钮Button('更换背景').position({x:'35%',y:'85%'}).onClick(()=>this.replaceBackground())}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}

六、注意事项

  1. 无需权限声明:PhotoViewPicker不需要在module.json5中声明READ_IMAGEVIDEO权限。
  2. URI有效期:返回的URI仅对当前应用有效,且有一定的生命周期,建议尽快读取。
  3. 内存管理:使用完毕的PixelMap应调用release()方法释放,避免内存泄漏。
  4. 大图片处理:对于大尺寸图片,建议通过ImageSourcedecodingOptions设置采样率。
  5. 用户取消处理:用户可能在选择器中点击取消,此时photoUris为空数组,需要判断处理。
  6. 数量限制maxSelectNumber最大值受系统限制,建议不超过200。

七、PhotoViewPicker vs PhotoAccessPicker

HarmonyOS中存在两种图片选择方式:

特性PhotoViewPickerfileIo + photoAccessHelper
权限声明不需要需要READ_IMAGEVIDEO
UI体验系统级选择器需自行实现
安全等级高(临时授权)需用户授权
适用场景普通图片选择深度相册管理

推荐:对于简单的图片选择需求,优先使用PhotoViewPicker。


八、完整工具类封装

以下是一个完整的图片选择工具类,可直接在项目中使用:

import{image}from'@kit.ImageKit';import{fileIo}from'@kit.CoreFileKit';import{photoAccessHelper}from'@kit.MediaLibraryKit';exportclassPhotoPickerUtil{/** * 从相册选择单张图片 */staticasyncpickSingleImage():Promise<image.PixelMap|undefined>{letpicker=newphotoAccessHelper.PhotoViewPicker();letoptions=newphotoAccessHelper.PhotoSelectOptions();options.MIMEType=photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;options.maxSelectNumber=1;letresult=awaitpicker.select(options);if(result.photoUris.length===0){returnundefined;}returnPhotoPickerUtil.uriToPixelMap(result.photoUris[0]);}/** * 从相册选择多张图片 */staticasyncpickMultipleImages(maxCount:number):Promise<image.PixelMap[]>{letpicker=newphotoAccessHelper.PhotoViewPicker();letoptions=newphotoAccessHelper.PhotoSelectOptions();options.MIMEType=photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;options.maxSelectNumber=maxCount;letresult=awaitpicker.select(options);letpixelMaps:image.PixelMap[]=[];for(leturiofresult.photoUris){letpm=awaitPhotoPickerUtil.uriToPixelMap(uri);pixelMaps.push(pm);}returnpixelMaps;}/** * 将URI转换为PixelMap */staticasyncuriToPixelMap(uri:string):Promise<image.PixelMap>{letfile=fileIo.openSync(uri);letstat=fileIo.statSync(file.fd);letbuffer=newArrayBuffer(stat.size);fileIo.readSync(file.fd,buffer);fileIo.closeSync(file.fd);letimageSource=image.createImageSource(buffer);returnawaitimageSource.createPixelMap({editable:true});}/** * 将URI转换为ArrayBuffer */staticuriToBuffer(uri:string):ArrayBuffer{letfile=fileIo.openSync(uri);letstat=fileIo.statSync(file.fd);letbuffer=newArrayBuffer(stat.size);fileIo.readSync(file.fd,buffer);fileIo.closeSync(file.fd);returnbuffer;}}

九、总结

PhotoViewPicker是HarmonyOS中从相册选择图片的最佳方案,核心要点:

  • 无需声明权限,通过系统级选择器实现安全选图。
  • 通过PhotoSelectOptions配置选择类型和数量限制。
  • 返回的photoUris数组包含选中图片的URI,可进一步转为PixelMap。
  • 注意及时释放PixelMap资源,防止内存泄漏。
  • 建议封装工具类,统一图片选择和处理逻辑。

在图片编辑类应用中,PhotoViewPicker通常用于"选择背景图"功能,与Stack贴纸叠加、componentSnapshot截图、SaveButton保存形成完整的工作流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/5 13:54:39

3PEAK思瑞浦 LM339-SO2R SOP14 比较器

特性 宽单电源电压范围或双电源:2V至40V或土1V至20V 低供电电流:每通道460uA(典型值) 传播延迟:1us 低偏置电压:4mV(最大值&#xff0c;-40C至85C) 低输入偏置电流:60nA(典型值)输入共模电压范围包含地线 内部差分输入电压范围等于供电电压 开漏输出以实现最大灵活性 低输出饱…

作者头像 李华
网站建设 2026/7/5 13:54:03

山东大学软件学院 2026 年数据库系统期末考试回忆版

ER图相比前几年要更复杂一些一、简答题 1. SQL 查询优化与语法树 给出SQL 语句&#xff0c;要求画出该查询的语法树&#xff0c;并直接给出优化后的语法树。(忘了&#xff0c;反正很简单) 2. 多值依赖 给定关系模式 R(A, B, C)&#xff0c;已知多值依赖&#xff1a; A ->>…

作者头像 李华
网站建设 2026/7/5 13:54:03

Burp Suite入门指南:从零掌握Web抓包与安全测试核心功能

1. 项目概述&#xff1a;为什么我们需要一个Web抓包工具在Web应用开发、安全测试甚至是日常的故障排查中&#xff0c;我们经常需要知道浏览器和服务器之间到底在“聊”些什么。一个按钮点击后&#xff0c;到底发送了哪些数据&#xff1f;登录请求里&#xff0c;密码是以什么格式…

作者头像 李华
网站建设 2026/7/5 13:45:04

redis的aof方式恢复

情况一&#xff1a;你本来就有 AOF 文件 如果你之前开启过 AOF&#xff08;或者有别人给的 appendonly.aof 文件&#xff09;&#xff0c;恢复步骤如下&#xff1a; 1. 准备 AOF 文件 # 将 AOF 文件放到目标数据目录 cp /path/to/appendonly.aof /www/server/redis/ chown redi…

作者头像 李华
网站建设 2026/7/5 13:44:04

Java安全管理器实战:从零构建OJ判题机安全沙箱

1. 项目概述&#xff1a;为什么需要自己搭建OJ判题机&#xff1f;做在线评测系统&#xff08;Online Judge&#xff0c; OJ&#xff09;的后端&#xff0c;最核心也最头疼的部分就是判题机。这玩意儿负责接收用户提交的代码&#xff0c;在一个安全、可控的环境里编译、运行&…

作者头像 李华