#HarmonyOS NEXT体验官# 图片选择方案 原创

奥尼5354
发布于 2025-3-10 22:59
浏览
0收藏

背景


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

#HarmonyOS NEXT体验官# 图片选择方案-鸿蒙开发者社区

项目架构

#HarmonyOS NEXT体验官# 图片选择方案-鸿蒙开发者社区

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

重要方法解析


调用相机拍照

  • 添加camera, cameraPicker的外部引用
import { camera, cameraPicker } from '@kit.CameraKit';
  • 1.
  • 使用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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

访问图库选择图片

  • 添加PromptActionClass的外部引用
import { PromptActionClass } from '../Common/PromptActionClass';
  • 1.
  • 使用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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

整体代码


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%')
  }

  @Builder
  PictureBuilder() {
    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;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.

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}`);
        }
      }
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.

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%")
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.

代码文件下载

ImageSelectDemo: 图片选择博客代码

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报


回复
    相关推荐