本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、PhotoPicker组件

   PhotoPicker组件是HarmonyOS中用于访问用户图片和视频资源的系统组件。可以将该组件嵌入应用界面,用户选择图片或视频后,组件直接返回资源URI,无需应用申请读取存储权限,实现了安全便捷的多媒体文件访问。

二、特性

  1. 零权限访问:用户授权选择后直接获取资源URI,无需申请相册读写权限

  2. 多媒体支持:同时支持图片和视频文件的选择

  3. 双视图模式

    • 宫格视图:显示缩略图列表

    • 大图视图:全屏预览选中的图片/视频

  4. 功能多

    • 内置搜索功能

    • 相机入口集成

    • 多选控制(设置最大选择数量)

    • 自定义UI样式

三、开发步骤

步骤1:导入必要模块

import {
  PhotoPickerComponent,    // 主组件
  PickerController,        // 组件控制器
  PickerOptions,           // 配置选项
  DataType,                // 数据类型
  BaseItemInfo,            // 基础项目信息
  ItemInfo,                // 项目信息
  PhotoBrowserInfo,        // 大图浏览器信息
  ItemType,                // 项目类型枚举
  ClickType,               // 点击类型枚举
  MaxCountType,            // 最大数量类型
  PhotoBrowserRange,       // 大图浏览范围
  ReminderMode,            // 提醒模式
  photoAccessHelper        // 照片访问助手
} from '@kit.MediaLibraryKit';

步骤2:创建组件实例和状态变量

@Entry
@Component
struct PhotoPickerComponentDemo {
  // 配置选项实例
  pickerOptions: PickerOptions = new PickerOptions();
  
  // 组件控制器实例
  @State pickerController: PickerController = new PickerController();
  
  // 已选择的图片URI列表
  @State selectUris: Array<string> = new Array<string>();
  
  // 当前查看的图片URI
  @State currentUri: string = '';
  
  // 是否显示大图模式
  @State isBrowserShow: boolean = false;
}

步骤3:初始化配置参数

在组件生命周期中配置PickerOptions:

aboutToAppear() {
  // 设置可选择的文件类型(图片和视频)
  this.pickerOptions.MIMEType = 
    photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;
  
  // 最大选择数量为5
  this.pickerOptions.maxSelectNumber = 5;
  
  // 超出最大选择数量时使用Toast提醒
  this.pickerOptions.maxSelectedReminderMode = ReminderMode.TOAST;
  
  // 显示搜索框
  this.pickerOptions.isSearchSupported = true;
  
  // 显示相机入口
  this.pickerOptions.isPhotoTakingSupported = true;
}

步骤4:回调函数(主要有8个)

1. onItemClicked - 项目点击回调
private onItemClicked(itemInfo: ItemInfo, clickType: ClickType): boolean {
  if (!itemInfo) return false;
  
  let type: ItemType | undefined = itemInfo.itemType;
  let uri: string | undefined = itemInfo.uri;
  
  if (type === ItemType.CAMERA) {
    // 点击相机项目
    return true; // true: 拉起系统相机; false: 应用自行处理
  } else {
    if (clickType === ClickType.SELECTED) {
      // 项目被选中
      if (uri) {
        this.selectUris.push(uri);
        this.pickerOptions.preselectedUris = [...this.selectUris];
      }
      return true; // true: 显示勾选状态
    } else {
      // 项目被取消选中
      if (uri) {
        this.selectUris = this.selectUris.filter((item: string) => item != uri);
        this.pickerOptions.preselectedUris = [...this.selectUris];
      }
    }
    return true;
  }
}
2. onEnterPhotoBrowser - 进入大图模式回调
private onEnterPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean {
  this.isBrowserShow = true;
  return true;
}
3. onExitPhotoBrowser - 退出大图模式回调
private onExitPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean {
  this.isBrowserShow = false;
  return true;
}
4. onPickerControllerReady - 控制器就绪回调
private onPickerControllerReady(): void {
  // 可在此处通过控制器定制组件行为
  // 例如:隐藏大图页的返回按钮
  let elements: number[] = [PhotoBrowserUIElement.BACK_BUTTON];
  this.pickerController.setPhotoBrowserUIElementVisibility(elements, false);
}
5. onPhotoBrowserChanged - 大图滑动切换回调
private onPhotoBrowserChanged(browserItemInfo: BaseItemInfo): boolean {
  this.currentUri = browserItemInfo.uri ?? '';
  return true;
}
6. onSelectedItemsDeleted - 已选项目被删除回调
private onSelectedItemsDeleted(baseItemInfos: Array<BaseItemInfo>): void {
  // 处理已选项目被用户删除的情况
}
7. onExceedMaxSelected - 超出最大选择数量回调
private onExceedMaxSelected(exceedMaxCountType: MaxCountType): void {
  // 处理用户尝试选择超过最大数量限制的情况
}
8. onCurrentAlbumDeleted - 当前相册被删除回调
private onCurrentAlbumDeleted(): void {
  // 处理当前浏览的相册被删除的情况
}

步骤5:构建UI界面

build() {
  Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
    // 1. PhotoPicker主组件
    PhotoPickerComponent({
      pickerOptions: this.pickerOptions,
      onItemClicked: (itemInfo: ItemInfo, clickType: ClickType): boolean => 
        this.onItemClicked(itemInfo, clickType),
      onEnterPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => 
        this.onEnterPhotoBrowser(photoBrowserInfo),
      onExitPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => 
        this.onExitPhotoBrowser(photoBrowserInfo),
      onPickerControllerReady: (): void => 
        this.onPickerControllerReady(),
      onPhotoBrowserChanged: (browserItemInfo: BaseItemInfo): boolean => 
        this.onPhotoBrowserChanged(browserItemInfo),
      onSelectedItemsDeleted: (baseItemInfos: Array<BaseItemInfo>) => 
        this.onSelectedItemsDeleted(baseItemInfos),
      onExceedMaxSelected: (exceedMaxCountType: MaxCountType) => 
        this.onExceedMaxSelected(exceedMaxCountType),
      onCurrentAlbumDeleted: () => 
        this.onCurrentAlbumDeleted(),
      pickerController: this.pickerController,
    })
    .width('100%')
    .height('80%')

    // 2. 底部控制栏(应用自定义)
    if (this.isBrowserShow) {
      // 大图模式下的底部缩略图栏
      Row() {
        ForEach(this.selectUris, (uri: string) => {
          if (uri === this.currentUri) {
            // 当前查看的图片:红色边框高亮
            Image(uri)
              .height(50)
              .width(50)
              .borderWidth(1)
              .borderColor('red')
          } else {
            // 其他已选图片:可点击切换
            Image(uri)
              .height(50)
              .width(50)
              .onClick(() => {
                // 更新选中列表并跳转到指定图片
                this.pickerController.setData(
                  DataType.SET_SELECTED_URIS, 
                  this.selectUris
                );
                this.pickerController.setPhotoBrowserItem(
                  uri, 
                  PhotoBrowserRange.ALL
                );
              })
          }
        }, (uri: string) => JSON.stringify(uri))
      }
      .alignSelf(ItemAlign.Center)
      .margin(this.selectUris.length ? 10 : 0)
    } else {
      // 宫格模式下的预览按钮
      Button('预览已选项目')
        .width('33%')
        .alignSelf(ItemAlign.Start)
        .height('5%')
        .margin(10)
        .onClick(() => {
          if (this.selectUris.length > 0) {
            // 跳转到大图模式,仅显示已选项目
            this.pickerController.setPhotoBrowserItem(
              this.selectUris[0], 
              PhotoBrowserRange.SELECTED_ONLY
            );
          }
        })
    }
  }
  .width('100%')
  .height('100%')
}

四、控制器(PickerController)常用方法

1. 控制大图模式元素可见性

// 隐藏大图页的返回按钮
let elements: number[] = [PhotoBrowserUIElement.BACK_BUTTON];
this.pickerController.setPhotoBrowserUIElementVisibility(elements, false);

2. 跳转到指定图片

// 跳转到指定URI的图片
// PhotoBrowserRange.ALL: 显示所有项目
// PhotoBrowserRange.SELECTED_ONLY: 仅显示已选项目
this.pickerController.setPhotoBrowserItem(uri, PhotoBrowserRange.ALL);

3. 更新选中列表

// 设置组件内部的选中URI列表
this.pickerController.setData(DataType.SET_SELECTED_URIS, this.selectUris);

4. 刷新数据

// 重新加载图片/视频数据
this.pickerController.setData(DataType.REFRESH, null);

五、注意事项

1. URI的只读性质

  • 回调函数返回的URI是只读URI,只能用于读取文件数据

  • 不能直接在回调中使用这些URI打开文件

  • 需要将URI保存到全局变量中,后续再使用

2. 文件属性获取

如果需要获取文件的元数据(大小、时间、路径等):

// 需要使用文件管理API
import fs from '@ohos.file.fs';
// 根据URI获取文件属性

3. 回调函数返回值

  • 返回 true:执行系统默认行为

  • 返回 false:阻止默认行为,由应用处理

4. 相机入口处理

当用户点击相机项目时:

  • 返回 true:自动调用系统相机

  • 返回 false:不调用系统相机,应用可自定义拍照逻辑

六、配置选项(PickerOptions)

主要配置项:

  • MIMEType:文件类型筛选

    • IMAGE_TYPE:仅图片

    • VIDEO_TYPE:仅视频

    • IMAGE_VIDEO_TYPE:图片和视频

  • maxSelectNumber:最大选择数量

  • maxSelectedReminderMode:超出限制提醒方式

    • ReminderMode.NONE:不提醒

    • ReminderMode.TOAST:Toast提示

    • ReminderMode.DIALOG:对话框提示

  • isSearchSupported:是否显示搜索框

  • isPhotoTakingSupported:是否显示相机入口

  • preselectedUris:预选中的URI列表

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐