当前位置: 首页 > news >正文

《图片添加贴纸》四、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保存形成完整的工作流。

http://www.cnnetsun.cn/news/3161567.html

相关文章:

  • 3PEAK思瑞浦 LM339-SO2R SOP14 比较器
  • 山东大学软件学院 2026 年数据库系统期末考试回忆版
  • Burp Suite入门指南:从零掌握Web抓包与安全测试核心功能
  • 多模型统一接入实战:Agent 开发如何用一套 API 搞定 DeepSeek、Qwen、GLM、Llama?
  • redis的aof方式恢复
  • Java安全管理器实战:从零构建OJ判题机安全沙箱
  • Windows EFS加密文件重装系统后恢复全攻略:原理、场景与实操
  • 抖音无水印视频下载终极指南:三步搞定批量下载难题
  • 影刀RPA新手教程:Python协同入门完全指南——不会Python也能在影刀里用Python
  • AI攻防时代:智能风控如何应对自动化攻击新范式
  • 标称网格的地理经纬度
  • HCI 功能规范【4.8. Versioned events】
  • 总目录 2026版国家级全领域科研痛点攻关
  • 第25篇:数据安全:从“边界防护”到“纵深防御”
  • 关于C++多重继承下虚表结构的问题
  • Redis分布式锁进阶第三十七篇
  • 奇迹 MU 剑与翼手游官网下载:奇迹 MU 剑与翼最新官方下载渠道
  • SRC漏洞挖掘入门:8种实战姿势与零基础进阶路径
  • Three.js 城市光影教程
  • 数学的本质是什么?——数学为什么如此不可思议地有效-龍德明宇
  • 主动推理-信息组织
  • SpringBoot3.x新特性解读与迁移指南
  • 影刀RPA深度教程:异常处理与调试完全指南
  • 泳池设备品牌哪家好
  • 《欠你的那场婚礼》 台剧|在线观看|电视剧|夸克|下载|豆瓣
  • 嵌入式系统2x2矩阵键盘设计与74HC32应用
  • 模型回滚流程:版本能切回去,数据也要对得上
  • LangGraph 工作流:用业务场景检验技术取舍
  • 2026年GEO贴牌代理源码解构:核心状态机深度拆解
  • SpringBoot项目从开发到部署的完整指南