【HarmonyOS Next】图片选择方案

news/2025/2/21 12:40:57/

背景


封装一个选择图片和调用拍照相机的按钮,展示api13下选择图片和调用相机,可以使用不申请用户权限的方式,进行图片的选择和修改。但是,目前方案并未包含上传图片保存的功能,仅提供图片选择或者拍照后,图片展示的一种方案。

在这里插入图片描述

项目架构

在这里插入图片描述

  • Common :公共操作类存放文件夹
  • PromptActionClass:全局弹窗操作类
  • components:公共弹窗组件文件夹
  • SelectImageDialog:选择图片弹窗组件
  • pages->Index:入口界面

重要方法解析


调用相机拍照

  • 添加camera, cameraPicker的外部引用
import { camera, cameraPicker } from '@kit.CameraKit';
  • 使用cameraPicker的pick方法实现安全调用设备相机,并返回选择结果cameraPicker.PickerResult对象,通过设置cameraPicker.PickerProfile对象属性实现对相机的初始化属性设置。
try {//配置相机设置let pickerProfile: cameraPicker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,};let result: cameraPicker.PickerResult =await cameraPicker.pick(getContext(), [cameraPicker.PickerMediaType.PHOTO],pickerProfile);if (result.resultCode == 0) {await this.UpdateShowImage(result.resultUri);}PromptActionClass.CloseDialog();return true;
} catch (e) {console.info(e);return false;
}

访问图库选择图片

  • 添加PromptActionClass的外部引用
import { PromptActionClass } from '../Common/PromptActionClass';
  • 使用photoAccessHelper.PhotoViewPicker对象的select方法,实现安全调用相册并选择图片。通过photoAccessHelper.PhotoSelectOptions对象,对选择方法进行初始化,可以设置默认选择、选择数量、选择类型等。
try {const photoSelectOpt = new photoAccessHelper.PhotoSelectOptions();//设置选择类型photoSelectOpt.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;//选择图片最大数量photoSelectOpt.maxSelectNumber = 1;//图片选择器const photoPicker = new photoAccessHelper.PhotoViewPicker();const selectResult: photoAccessHelper.PhotoSelectResult = await photoPicker.select(photoSelectOpt)let uri: string = "";if (selectResult.isOriginalPhoto || selectResult.photoUris.length == 0) {return false;}uri = selectResult.photoUris[0];await this.UpdateShowImage(uri);PromptActionClass.CloseDialog();return true;
} catch (e) {console.info(e);return false;
}

整体代码


Index

import { image } from '@kit.ImageKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { PromptActionClass } from '../Common/PromptActionClass';
import { SelectImageDialog } from '../components/SelectImageDialog';
import { camera, cameraPicker } from '@kit.CameraKit';@Entry
@ComponentV2
struct Index {@Local ShowImage: ResourceStr | PixelMap = $r('app.media.AddImageIcon')aboutToAppear(): void {PromptActionClass.SetContext(this.getUIContext());PromptActionClass.SetOptions({builder: () => {this.PictureBuilder()},alignment: DialogAlignment.Bottom,cornerRadius: {topLeft: 20,topRight: 20,bottomLeft: 20,bottomRight: 20},height: 154,width: "90%",})}build() {RelativeContainer() {Button() {Image(this.ShowImage).width("100%").borderRadius(20).padding(10)}.width(120).height(120).type(ButtonType.Normal).backgroundColor(Color.White).borderWidth(3).borderColor('#592708').borderRadius(20).id("AddImageBtn").alignRules({middle: { anchor: "__container__", align: HorizontalAlign.Center }}).margin({ top: 20 }).onClick(() => {PromptActionClass.OpenDialog();})}.height('100%').width('100%')}@BuilderPictureBuilder() {SelectImageDialog({CancelEvent: async () => {try {PromptActionClass.CloseDialog();return true;} catch (e) {console.info(e);return false;}},TakePictureEvent: async () => {try {//配置相机设置let pickerProfile: cameraPicker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,};let result: cameraPicker.PickerResult =await cameraPicker.pick(getContext(), [cameraPicker.PickerMediaType.PHOTO],pickerProfile);if (result.resultCode == 0) {await this.UpdateShowImage(result.resultUri);}PromptActionClass.CloseDialog();return true;} catch (e) {console.info(e);return false;}},SelectedPictureEvent: async () => {try {const photoSelectOpt = new photoAccessHelper.PhotoSelectOptions();//设置选择类型photoSelectOpt.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;//选择图片最大数量photoSelectOpt.maxSelectNumber = 1;//图片选择器const photoPicker = new photoAccessHelper.PhotoViewPicker();const selectResult: photoAccessHelper.PhotoSelectResult = await photoPicker.select(photoSelectOpt)let uri: string = "";if (selectResult.isOriginalPhoto || selectResult.photoUris.length == 0) {return false;}uri = selectResult.photoUris[0];await this.UpdateShowImage(uri);PromptActionClass.CloseDialog();return true;} catch (e) {console.info(e);return false;}}})}async UpdateShowImage(uri: string) {let file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY)const imageSourceApi = image.createImageSource(file.fd);let map: PixelMap = await imageSourceApi.createPixelMap();this.ShowImage = map;}
}

PromptActionClass

import { promptAction } from "@kit.ArkUI";
import { BusinessError } from "@kit.BasicServicesKit";/*** 弹窗操作类*/
export class PromptActionClass {/***展示界面的ID集合*/private static ShowIDArray: number[] = [];static Context: UIContext;/*** 弹窗界面设置*/static Options: promptAction.CustomDialogOptions;static SetContext(context: UIContext) {PromptActionClass.Context = context;}static SetOptions(options: promptAction.CustomDialogOptions) {PromptActionClass.Options = options;}/*** 弹窗*/static OpenDialog() {if (PromptActionClass.Options) {PromptActionClass.Context.getPromptAction().openCustomDialog(PromptActionClass.Options).then((id: number) => {PromptActionClass.ShowIDArray.push(id);console.info('弹窗已打开')}).catch((error: BusinessError) => {let message = (error as BusinessError).message;let code = (error as BusinessError).code;console.error(`弹窗失败,错误代码是:${code}, message 是 ${message}`);})}}/*** 关闭弹窗*/static CloseDialog() {if (PromptActionClass.ShowIDArray.length != 0) {try {PromptActionClass.Context.getPromptAction().closeCustomDialog(PromptActionClass.ShowIDArray[PromptActionClass.ShowIDArray.length-1])console.info('成功关闭弹窗.')} catch {(error: BusinessError) => {let message = (error as BusinessError).message;let code = (error as BusinessError).code;console.error(`弹窗关闭失败,错误代码:${code}, message 是 ${message}`);}}}}
}

SelectImageDialog

@ComponentV2
export struct SelectImageDialog {@Event TakePictureEvent: () => Promise<boolean> = async () => {return false;}@Event SelectedPictureEvent: () => Promise<boolean> = async () => {return false;}@Event CancelEvent: () => Promise<boolean> = async () => {return false;}build() {RelativeContainer() {Button("拍照").type(ButtonType.Normal).width("100%").id("TakePictureBtn").backgroundColor("#ffffff").height(50).fontColor("#343434").alignRules({bottom: { anchor: "SelectedPictureBtn", align: VerticalAlign.Top }}).onClick(async () => {await this.TakePictureEvent();})Button("从相册中选择").type(ButtonType.Normal).width("100%").height(50).id("SelectedPictureBtn").backgroundColor("#ffffff").fontColor("#343434").borderWidth({ bottom: 2, top: 2 }).borderColor("#f6f6f6").alignRules({center: { anchor: "__container__", align: VerticalAlign.Center }}).onClick(async () => {await this.SelectedPictureEvent();})Button("取消").width("100%").type(ButtonType.Normal).height(50).backgroundColor("#ffffff").fontColor("#aeaeae").alignRules({top: { anchor: "SelectedPictureBtn", align: VerticalAlign.Bottom }}).onClick(async () => {await this.CancelEvent();})}.height("100%").width("100%")}
}

图片资源

从绑定资源中下载

代码文件下载

ImageSelectDemo: 图片选择博客代码


http://www.ppmy.cn/news/1573454.html

相关文章

PostgreSQL认证指南

PostgreSQL 作为一款强大的开源关系型数据库&#xff0c;深受开发者和企业的青睐。获得 PostgreSQL 专家认证&#xff0c;不仅能提升个人在数据库领域的专业能力&#xff0c;还能为职业发展增添有力筹码。下面为大家详细介绍 PostgreSQL 专家认证的学习路径。 一、深入理解基础…

c/c++蓝桥杯经典编程题100道(22)最短路径问题

最短路径问题 ->返回c/c蓝桥杯经典编程题100道-目录 目录 最短路径问题 一、题型解释 二、例题问题描述 三、C语言实现 解法1&#xff1a;Dijkstra算法&#xff08;正权图&#xff0c;难度★★&#xff09; 解法2&#xff1a;Bellman-Ford算法&#xff08;含负权边&a…

腾讯的webUI怎样实现deepseek外部调用 ; 腾讯云通过API怎样调用deepseek

腾讯的webUI怎样实现deepseek外部调用 目录 腾讯的webUI怎样实现deepseek外部调用腾讯云通过API怎样调用deepseekhtml方式curl方式python方式腾讯云通过API怎样调用deepseek 重点说明:不需要SK,仅仅使用ip和端口号 html方式 <!DOCTYPE html> <html lang="e…

QT移植,交叉编译至泰山派RK3566开发板,.pro文件解析

配置文件解析 配置文件丢这里,后面有空整理下。 说下大概的注意点, 安装路径(qtcreator远程部署的路径)、 动态库路径和头文件路径、 运行时动态库路径和头文件路径($$pwd在编译后会被换成绝对路径,因此需要指定运行时动态库路径) # 指定使用的 Qt 模块 QT +=…

STM32 外部中断和NVIC嵌套中断向量控制器

目录 背景 外部中断/事件控制器(EXTI) 主要特性 功能说明 外部中断线 嵌套向量中断控制器 特性 ‌中断线&#xff08;Interrupt Line&#xff09; 中断线的定义和作用 STM32中断线的分类和数量 优先级分组 抢占优先级&#xff08;Preemption Priority&#xff09; …

Go语言实现单例模式

单例模式 单例模式分为饿汉和懒汉模式&#xff0c;前者是在程序启动的时候就初始化一个单例对象&#xff0c;后者是使用到这个单例的时候&#xff0c;才会初始化一个单例对象。 饿汉模式 package mainimport "fmt"type Singleton struct { }var instance *Singleto…

deepseek-r1落地指南(搭建web-ui | 搭建本地代码编辑器)

deepseek-r1落地指南&#xff08;搭建web-ui | 搭建本地代码编辑器&#xff09; 写在前面 前两天写了一篇《deepseek-r1本地部署指南》&#xff0c;今天就deepseek-r1本地部署&#xff0c;讲解一下本地部署的大模型如何落地&#xff08;应用&#xff09;&#xff0c;以便提高工…

NLLB 与 ChatGPT 双向优化:探索翻译模型与语言模型在小语种应用的融合策略

作者&#xff1a;来自 vivo 互联网算法团队- Huang Minghui 本文探讨了 NLLB 翻译模型与 ChatGPT 在小语种应用中的双向优化策略。首先介绍了 NLLB-200 的背景、数据、分词器和模型&#xff0c;以及其与 LLM&#xff08;Large Language Model&#xff09;的异同和协同关系。接着…