HarmonyOS APP《画伴梦工厂》开发第10篇:相册选择与 PhotoViewPicker——从相册导入图片

📅 2026/6/30 2:08:51
HarmonyOS APP《画伴梦工厂》开发第10篇:相册选择与 PhotoViewPicker——从相册导入图片
第2.2篇相册选择与 PhotoViewPicker——从相册导入图片难度⭐⭐ 进阶前置知识第 2.1 篇 相机开发实战涉及源文件products/default/src/main/ets/components/CreationComponents.ets概述第 2.1 篇我们学习了如何调用系统相机拍照。本篇将介绍另一种图片采集方式——通过PhotoViewPicker从相册中选择图片。与相机模式相比相册选择不需要繁重的CAMERA权限甚至不需要READ_MEDIA权限这得益于 HarmonyOS 的 Scope作用域访问模型。两者最终共用同一套capturePhoto处理流程保持了代码的高度复用。一、相机 vs 相册场景对比对比维度相机拍照相册选择权限需求ohos.permission.CAMERA无需额外权限Scope 访问用户操作打开相机 → 按快门 → 确认打开相册 → 点选图片 → 确认返回数据AbilityResult需多层解析PhotoSelectResult.photoUris直接获取适用场景用户手中有纸质画作用户之前拍好 / 截好的图片交互链路较长涉及系统相机界面较短Picker 浮层直接选择数据安全性完整文件路径Scope URI应用只能访问选中文件二、PhotoViewPicker 的基本使用2.1 权限检查与相机不同相册选择不需要READ_MEDIA权限。PermissionGuard.requestAlbum的实现非常简洁——直接返回授权成功// PermissionGuard.etsstaticasyncrequestAlbum(context:common.UIAbilityContext):PromisePermissionResult{// PhotoViewPicker grants scoped access to the selected media item.// Do not declare broad media-read permissions here; some devices reject them at install time.return{granted:true,message:};}设计理念PhotoViewPicker采用 Scope 访问模式。用户通过 Picker 选中的图片应用仅获得该特定文件的访问权限而不是整个媒体库的读取权限。这既保护了用户隐私又简化了开发者的权限管理工作。2.2 创建并配置 PhotoSelectOptionsconstphotoSelectOptionsnewphotoAccessHelper.PhotoSelectOptions();photoSelectOptions.MIMETypephotoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;photoSelectOptions.maxSelectNumber1;photoSelectOptions.isPhotoTakingSupportedfalse;配置参数说明参数值含义MIMETypePhotoViewMIMETypes.IMAGE_TYPE只显示图片文件过滤视频和其他类型maxSelectNumber1单选模式一次只选一张图isPhotoTakingSupportedfalse不显示内置的拍照入口保持交互简洁2.3 调用 select 方法constphotoViewPickernewphotoAccessHelper.PhotoViewPicker();photoViewPicker.select(photoSelectOptions).then((result:photoAccessHelper.PhotoSelectResult){if(result.photoUris.length0){this.noticeText未选择图片请重新从相册导入;return;}this.capturePhoto(result.photoUris[0],相册图片);this.noticeText相册导入完成已用选中图片覆盖当前预览;}).catch((){this.noticeText相册选择失败请重新从相册导入;});返回结果处理PhotoSelectResult的结构interfacePhotoSelectResult{photoUris:string[];// 选中图片的 URI 数组isOriginalPhoto:boolean;// 是否为原图可选字段}result.photoUris[0]因为配置了maxSelectNumber 1数组至多一个元素直接取第一个。空数组检查用户可能取消选择或从选择界面返回需要处理这种情况。错误处理catch分支处理系统 Picker 异常如相册无法打开。三、openAlbum 完整方法将以上步骤组合得到openAlbum的完整实现privateasyncopenAlbum(){constcontextgetContext(this)ascommon.UIAbilityContext;constpermissionResult:PermissionResultawaitPermissionGuard.requestAlbum(context);if(!permissionResult.granted){this.noticeTextpermissionResult.message;return;}constphotoSelectOptionsnewphotoAccessHelper.PhotoSelectOptions();photoSelectOptions.MIMETypephotoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;photoSelectOptions.maxSelectNumber1;photoSelectOptions.isPhotoTakingSupportedfalse;constphotoViewPickernewphotoAccessHelper.PhotoViewPicker();photoViewPicker.select(photoSelectOptions).then((result:photoAccessHelper.PhotoSelectResult){if(result.photoUris.length0){this.noticeText未选择图片请重新从相册导入;return;}this.capturePhoto(result.photoUris[0],相册图片);this.noticeText相册导入完成已用选中图片覆盖当前预览;}).catch((){this.noticeText相册选择失败请重新从相册导入;});}四、与相机共用同一套处理流程无论图片来自相机还是相册都通过capturePhoto方法统一处理privatecapturePhoto(uri:string,sourceLabel:string拍照图片){if(uri!){this.capturedImageUriuri;this.imageSourceLabelsourceLabel;// 标记来源拍照图片 或 相册图片}this.hasPhototrue;this.activeStep1;this.generationProgress35;this.noticeText已采集画作可以直接生成动画;}这种设计的好处统一状态管理无论图片来源如何hasPhoto、activeStep、generationProgress等状态均为一致区分来源imageSourceLabel记录了来源信息UI 层可以展示已使用拍照图片或已使用相册图片降低复杂度后续的生成流程不需要关心图片从哪来只需使用capturedImageUri五、UI 层触发在界面上用户通过相册导入按钮触发Button(相册导入).height(46).fontSize(14).fontWeight(FontWeight.Bold).fontColor(#FFFFFF).backgroundColor(this.mint)// #42CDA3 绿色按钮.borderRadius(23).layoutWeight(1).margin({left:10}).onClick((){if(!this.recognizing){this.openAlbum();}})拍照采集和相册导入两个按钮并排显示在画作预览区下方用户可以根据手头情况自由选择┌────────────────────────────────┐ │ [ 拍照采集 ] [ 相册导入 ] │ └────────────────────────────────┘六、完整流程时序图用户点击相册导入 │ ▼ PermissionGuard.requestAlbum() → 直接返回 granted │ ▼ new PhotoViewPicker().select(options) │ ├── 用户取消 → noticeText 提示 → 结束 │ └── 用户选择图片 │ ▼ result.photoUris[0] 获取 URI │ ▼ capturePhoto(uri, 相册图片) │ ▼ hasPhoto true activeStep 1 generationProgress 35 imageSourceLabel 相册图片七、常见问题排查7.1 图片未显示确认capturedImageUri是否赋值正确检查 URI 格式PhotoViewPicker返回的 URI 可直接用于Image组件的src属性确认Image组件设置了合适的objectFit如ImageFit.Cover或ImageFit.Contain7.2 相册打不开在真机上测试模拟器相册功能可能受限检查kit.MediaLibraryKit是否已在模块中正确引入7.3 Scope URI 与文件路径PhotoViewPicker返回的 URI 是 Scope URI不能直接用于fileIo等文件操作如需文件操作需通过fileIo.fopen或沙箱路径转换在本项目中URI 直接传给Image组件和后续RecognitionWaitingPage展示无需文件级操作总结本文介绍了使用PhotoViewPicker从相册选择图片的方案与第 2.1 篇的相机拍照形成互补知识点实现方式Picker 配置PhotoSelectOptions设置 MIME、选择数、拍照按钮调用方式PhotoViewPicker.select()返回 Promise结果获取PhotoSelectResult.photoUris直接获取权限模型Scope 访问无需READ_MEDIA权限流程复用与相机共用capturePhoto统一处理两种图片采集方式覆盖了用户不同的使用场景——手中有纸质画作用相机拍手机里已有图片从相册选。下一节我们将进入自由涂鸦模式学习如何在 ArkUI 中实现完整的绘画体验。