HarmonyOS鸿蒙Next中批量选择图片上传

HarmonyOS鸿蒙Next中批量选择图片上传 想要批量的选择大量的图片进行上传,批量选择,picker可以做到吗?

6 回复

【问题剖析】

你好,选择器(picker)支持批量选取操作,核心在于设定最大可选数量,该数值默认是 50,上限为 500。获取图片最好用安全控件,官方是提供文档的:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/component-guidelines-photoviewpicker

【解决代码】

完整的代码

import {
  PhotoPickerComponent,
  PickerController,
  PickerOptions,
  DataType,
  BaseItemInfo,
  ItemInfo,
  PhotoBrowserInfo,
  ItemType,
  ClickType,
  MaxCountType,
  PhotoBrowserRange,
  ReminderMode,
  photoAccessHelper
} from '@kit.MediaLibraryKit';

@Entry
@Component
struct PhotoPickerComponentDemo {
  // 组件初始化时设置参数信息。
  pickerOptions: PickerOptions = new PickerOptions();

  // 组件初始化完成后,可控制组件部分行为。
  @State pickerController: PickerController = new PickerController();

  // 已选择的图片。
  @State selectUris: Array<string> = new Array<string>();

  // 目前选择的图片。
  @State currentUri: string = '';

  // 是否显示大图。
  @State isBrowserShow: boolean = false;

  aboutToAppear() {
    // 设置picker宫格页数据类型
    this.pickerOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE // 图片和照片都显示。
    // 最大选择数量。
    this.pickerOptions.maxSelectNumber = 5;
    // 超出最大选择数量时。
    this.pickerOptions.maxSelectedReminderMode = ReminderMode.TOAST;
    // 是否展示搜索框,默认false。
    this.pickerOptions.isSearchSupported = true;
    // 是否支持拍照,默认false。
    this.pickerOptions.isPhotoTakingSupported = true;

  }

  // 资源被选中回调,返回资源的信息,以及选中方式。
  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) {
      // 点击相机item。
      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) => {
            return item != uri;
          });
          this.pickerOptions.preselectedUris = [...this.selectUris];
        }
      }
      return true;
    }
  }

  // 进入大图的回调。
  private onEnterPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean {
    this.isBrowserShow = true;
    return true;
  }

  // 退出大图的回调。
  private onExitPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean {
    this.isBrowserShow = false;
    return true;
  }

  // 接收到该回调后,便可通过pickerController相关接口向picker发送数据,在此之前不生效。
  private onPickerControllerReady(): void {
  }

  // 大图左右滑动的回调。
  private onPhotoBrowserChanged(browserItemInfo: BaseItemInfo): boolean {
    this.currentUri = browserItemInfo.uri ?? '';
    return true;
  }

  // 已勾选图片被删除时的回调。
  private onSelectedItemsDeleted(baseItemInfos: Array<BaseItemInfo>): void {
  }

  // 超过最大选择数量再次点击时的回调。
  private onExceedMaxSelected(exceedMaxCountType: MaxCountType): void {
  }

  // 当前相册被删除时的回调。
  private onCurrentAlbumDeleted(): void {
  }

  build() {
    Flex({
      direction: FlexDirection.Column,
      alignItems: ItemAlign.Start
    }) {
      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: (BaseItemInfo: Array<BaseItemInfo>) => this.onSelectedItemsDeleted(BaseItemInfo),
        onExceedMaxSelected: (exceedMaxCountType: MaxCountType) => this.onExceedMaxSelected(exceedMaxCountType),
        onCurrentAlbumDeleted: () => this.onCurrentAlbumDeleted(),
        pickerController: this.pickerController,
      })

      // 这里模拟应用侧底部的选择栏。
      if (this.isBrowserShow) {
        // 已选择的图片缩略图。
        Row() {
          ForEach(this.selectUris, (uri: string) => {
            if (uri === this.currentUri) {
              Image(uri).height(50).width(50)
                .onClick(() => {
                })
                .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);
          }
        })
      }
    }
  }
}

更多关于HarmonyOS鸿蒙Next中批量选择图片上传的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


【问题分析】

picker是可以做到批量选择的,主要是设置好最大的选择数量,默认是50个最大为500

cke_2386.png

cke_2636.png

【解决方案】

楼主可以自行配置选择器的属性以及图片选择限制

let PhotoSelectOptions = new photoAccessHelper.PhotoSelectOptions()
PhotoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE
PhotoSelectOptions.maxSelectNumber = this.selectPhotoMaxNumber//配置最多能选择的数量
PhotoSelectOptions.isOriginalSupported = true
PhotoSelectOptions.subWindowName = '选择上传图片'
import { taskCamp } from '../../task/taskCamp';
import { http } from '@kit.NetworkKit';
import { fileModel } from '../../model/fileModel'

import {
  PhotoPickerComponent,
  PickerController,
  PickerOptions,
  DataType,
  ItemInfo,
  ItemType,
  PhotoBrowserInfo,
  ClickType,
  PickerColorMode,
  MaxSelected,
  MaxCountType,
  ReminderMode,
  PickerOrientation,
  SelectMode,
} from '@ohos.file.PhotoPickerComponent';
import photoAccessHelper from '@ohos.file.photoAccessHelper';
import { router } from '@kit.ArkUI';
import { UtilsAlert } from '../../utils/UtilsAlert'

@Entry
@CustomDialog
export default struct ShowAlbumPicker{
  // 组件初始化时设置参数信息
  pickerOptions: PickerOptions = new PickerOptions();
  @State imgArr: string[] = [];
  // 组件初始化完成后,可控制组件部分行为
  @State pickerController: PickerController = new PickerController();
  ShowAlbumPicker: CustomDialogController = new CustomDialogController({
    builder: ShowAlbumPicker(),
    alignment: DialogAlignment.BottomStart,
    width: '100%',
    height: '100%',
    customStyle:true
  });
  @State private userAccount: string = '';
  @State private passWord: string = '';
  showAlbumPickerBack?: (arr:string[]) => void;
  controller: CustomDialogController;

  // 组件生命周期
  aboutToDisappear() {
    if (this.showAlbumPickerBack) {
      this.showAlbumPickerBack(this.imgArr);
    }
  }

  async aboutToAppear() {

    // 设置picker宫格页数据类型
    this.pickerOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;

    // 是否展示搜索框,默认false
    this.pickerOptions.isSearchSupported = true;

    // 是否支持拍照,默认false
    this.pickerOptions.isPhotoTakingSupported = false;

    // 是否支持重复选择
    this.pickerOptions.isRepeatSelectSupported = false;

    // 最大选择数量
    this.pickerOptions.maxSelectNumber = 15; // 最大选择数量

    // 最大图片选择数量
    this.pickerOptions.maxPhotoSelectNumber = 15; // 最大图片选择数量

    // 最大视频选择数量
    this.pickerOptions.maxVideoSelectNumber = 15; // 最大视频选择数量

    // 超出最大选择数量时
    this.pickerOptions.maxSelectedReminderMode = ReminderMode.TOAST;

    // 设置大图背景色
    this.pickerOptions.photoBrowserBackgroundColorMode = PickerColorMode.AUTO;

    // 设置checkbox选中颜色
    this.pickerOptions.checkBoxColor = '#000000';

    // 设置checkbox文字颜色
    this.pickerOptions.checkboxTextColor = '#000000';

    // 设置宫格页背景色
    this.pickerOptions.backgroundColor = '#ffffff';

    // 设置选择模式,默认:MULTI_SELECT
    this.pickerOptions.selectMode = SelectMode.MULTI_SELECT;
    console.log('组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。');
  }

  // 进入大图页回调
  private onEnterPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean {
    console.info('onEnterPhotoBrowser' + JSON.stringify(photoBrowserInfo));
    return false;
  }

  // 退出大图页回调
  private onExitPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean {
    console.info('onExitPhotoBrowser' + JSON.stringify(photoBrowserInfo));
    return false;
  }

  // 接收到该回调后,便可通过pickerController相关接口向picker发送数据,在此之前不生效。
  private onPickerControllerReady(): void {
    console.info('onPickerControllerReady');
  }

  // 大图页图片切换回调事件处理
  private onPhotoBrowserChanged(photoBrowserItemInfo: ItemInfo): boolean {
    console.info('onPhotoBrowserChanged' + JSON.stringify(photoBrowserItemInfo));
    // this.currentUri = photoBrowserItemInfo.uri ?? '';
    return true;
  }

  // 图片/视频被选中的回调,返回的url只有只读权限,不能用url直接去打开
  private onSelect(uri: string): void {
    if (uri) {
      this.imgArr.push(uri);
      console.log(uri);
      // this.selectedUris.push(uri)
    }
    // 将uri保存起来,并保证切换不同的宫格页组件时保持选中项一致
    // this.pickerOptions.preselectedUris = [...this.selectedUris];
    // this.pickerOptions1.preselectedUris = [...this.selectedUris];
    // this.pickerOptions2.preselectedUris = [...this.selectedUris];
    // console.info('onSelect' + JSON.stringify(this.selectedUris));
  }

  // 图片/视频被取消勾选的回调,返回的url只有只读权限,不能用url直接去打开
  private onDeselect(uri: string): void {
    if (uri) {
      let imgIndex = this.imgArr.indexOf(uri);
      this.imgArr.splice(imgIndex);
      console.log('取消的图片:' + uri);
      // this.selectedUris = this.selectedUris.filter((item: string) => {
      //   return item !== uri;
      // })
    }
    // 排除反勾选uri,并保证切换不同的宫格页组件时保持选中项一致
    // this.pickerOptions.preselectedUris = [...this.selectedUris];
    // this.pickerOptions1.preselectedUris = [...this.selectedUris];
    // this.pickerOptions2.preselectedUris = [...this.selectedUris];
    // console.info('onDeselect' + JSON.stringify(this.selectedUris));
  }

  /**
   * 图片/视频被选中回调,返回资源的信息,以及选中方式
   * ItemInfo 图片、视频相关信息
   * ClickType(SELECTED:勾选, DESELECTED: 反选)
   * return 返回值为true时才会给url授权(返回的uri权限是只读权限)
   */
  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) { // 点击相机item
      console.info('onCameraClick');
      // if (this.isBlock) {
      //   return false;
      // }
      // 返回true则拉起系统相机,若应用需要自行处理则返回false。
      return true;
    } else if (type === ItemType.THUMBNAIL) { //点击图片、视频item(缩略图item)
      if (clickType === ClickType.SELECTED) { //选中
        // if (this.isBlock) {
        //   return false;
        // }
        // 将uri保存起来,并保证切换不同的宫格页组件时保持选中项一致
        if (uri) {
          // this.selectedUris.push(uri)
          // this.pickerOptions.preselectedUris = [...this.selectedUris];
          // this.pickerOptions1.preselectedUris = [...this.selectedUris];
          // this.pickerOptions2.preselectedUris = [...this.selectedUris];
        }
      } else { //反选
        if (uri) {
          // 排除反勾选uri,并保证切换不同的宫格页组件时保持选中项一致
          // this.selectedUris = this.selectedUris.filter((item: string) => {
          //   return item !== uri;
          // })
          // this.pickerOptions.preselectedUris = [...this.selectedUris];
          // this.pickerOptions1.preselectedUris = [...this.selectedUris];
          // this.pickerOptions2.preselectedUris = [...this.selectedUris];
        }
      }
    } else {
    }
    console.info('onItemClicked' + JSON.stringify(itemInfo));
    return true;
  }

  build() {
    Column() {
      Column() {
        Row() {
          Column() {
            Button('关闭', { type: ButtonType.Capsule, stateEffect: true })
              .borderRadius(8)
              .backgroundColor(0x317aff)
              .width(60)
              .height(32)
              .backgroundColor($r('app.color.green_default'))
              .onClick(() => {
                this.controller.close();
              })
              .margin({ left: 15 })
          }
          .width('15%')
          .height(30)
          .margin({ bottom: 15 })
          .alignItems(HorizontalAlign.Start)
          Column() {
            Text('')
              .fontSize(16)
              .fontWeight(FontWeight.Regular)
              .fontColor(Color.Black)// .margin({ left: 50, right: -50, bottom: 10 })
              .lineHeight(30)
              .textAlign(TextAlign.Center)
              .width('100%')
              .maxLines(1)
              .textOverflow({ overflow: TextOverflow.Clip })
          }.width('70%').height(30)
          .margin({ bottom: 15 })

          Column() {
            Button('确定', { type: ButtonType.Capsule, stateEffect: true })
              .borderRadius(8)
              .backgroundColor(0x317aff)
              .width(60)
              .height(32)
              .backgroundColor($r('app.color.green_default'))
              .onClick(() => {
                        if(this.imgArr.length == 0)
                        {
                          UtilsAlert.showMessage('没有选择图片');
                          return;
                        }
                        this.controller.close();
              })
              .margin({ right: 15 })
          }
          .width('15%')
          .height(30)
          .margin({ bottom: 15 })
          .alignItems(HorizontalAlign.End)
        }.width('100%').height(69).backgroundColor(Color.White).alignItems(VerticalAlign.Bottom)

        Row() {
          Divider()
            .margin({ bottom: 0 })
            .strokeWidth(1)
            .color($r('app.color.gray_line'))
            .width("100%")
        }.height(1).width('100%')
      }.width('100%').height(70).margin({top:30})


      Column() {
        PhotoPickerComponent({
          // 设置组件选择选项实例
          pickerOptions: this.pickerOptions,

          // 资源被选中回调,返回url信息(返回的uri权限是只读权限)
          onSelect: (uri: string): void => this.onSelect(uri),


          // 资源被反选回调,返回url信息(返回的uri权限是只读权限)
          onDeselect: (uri: string): void => this.onDeselect(uri),

          /**
           * 资源被选中回调,返回资源的信息,以及选中方式
           * ItemInfo(itemType, uri, mimeType, width, height, size, duration)
           * ClickType(SELECTED:勾选, DESELECTED: 反选)
           * return 返回值为true时才会给url授权(返回的uri权限是只读权限)
           */
          onItemClicked: (itemInfo: ItemInfo, clickType: ClickType): boolean => this.onItemClicked(itemInfo, clickType),

          /**
           * 进入大图页回调,
           * PhotoBrowserInfo (animatorParams: 动效)
           */
          onEnterPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => this.onEnterPhotoBrowser(photoBrowserInfo),

          /**
           * 退出大图页回调,
           * PhotoBrowserInfo (animatorParams: 动效)
           */
          onExitPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => this.onExitPhotoBrowser(photoBrowserInfo),

          /**
           * 切换大图页内容回调事件,
           * PhotoBrowserInfo (animatorParams: 动效)
           */
          // onPhotoBrowserChanged: (photoBrowserItemInfo: BaseItemInfo): boolean => this.onPhotoBrowserChanged(photoBrowserItemInfo),

          // 接收到该回调后,便可通过pickerController相关接口向picker发送数据,在此之前不生效。
          onPickerControllerReady: (): void => this.onPickerControllerReady(),

          // picker控制实例,应用可通过PickerController向picker组件发送数据,实现控制PhotoPickerComponent组件行为
          pickerController: this.pickerController,
        }).backgroundColor(Color.White).width('100%').height('100%')
      }.height('100%').width('100%').backgroundColor(Color.White)
      .margin({top:20})
    }.backgroundColor(Color.White).width('100%').height('100%')
  }

  postFIle() {
    if(this.imgArr.length == 0)
    {
      // AlertDialog.show({title:'',message:'你没有选择图片',isModal:false});
      UtilsAlert.showMessage('你没有选择图片');
      // AlertDialog.apply(1)
      return;
    }
    let task = new taskCamp();
    let params = "cotentType=0";
    let filePaths = this.imgArr;
    task.campPostFile(params, filePaths, (data: http.HttpResponse) => {
      if (data.result != 'NO') {
        let file: fileModel = data.result as fileModel;
        this.controller.close();
        if (this.showAlbumPickerBack) {
          this.showAlbumPickerBack(this.imgArr);
        }

      } else {
        UtilsAlert.showMessage('上传失败 请检查图片格式是否正确');
        // AlertDialog.show({ title: '', message: '上传失败 请检查图片格式是否正确' });
      }
    })
  }
}

你自己改一下就行 把task的部分换成自己的网络接口。

可以批量选择图片,但单次操作最多选择500个文件。​

具体限制如下:

  1. 文档选择器 (DocumentViewPicker)

    • 通过 DocumentSelectOptionsmaxSelectNumber 参数配置。
    • 最大数量上限为 500 个文件
    • 有效值范围:1-500。
    • 默认值为 500。
  2. 图库选择器 (PhotoViewPicker)

    • 通过 PhotoSelectOptionsmaxSelectNumber 参数配置。
    • 最大数量上限为 500 个文件
    • 默认值为 50(若不设置则默认为50,但最大可设为500)。

配置示例:

// 使用DocumentViewPicker批量选择文档/图片
let documentSelectOptions = new picker.DocumentSelectOptions();
documentSelectOptions.maxSelectNumber = 500; // 设置最大选择数量

// 使用PhotoViewPicker批量选择图片/视频
let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
photoSelectOptions.maxSelectNumber = 500; // 设置最大选择数量

注意事项:

  • 选择器返回的是文件URI列表,具有临时读取权限。
  • 若需持久化访问,需申请持久化权限。

在HarmonyOS Next中,可通过PhotoViewPicker实现批量图片选择。调用select方法并设置PhotoSelectOptions参数,指定maxSelectNumber限制选择数量。使用PhotoSelectResult接收返回的URI列表,通过FileManager将图片文件上传至目标服务器。整个过程基于ArkTS实现,无需依赖Java或C语言。

在HarmonyOS Next中,可以通过PhotoViewPicker实现批量选择图片上传。具体步骤如下:

  1. 创建PhotoViewPicker实例

    let photoPicker = new picker.PhotoViewPicker();
    
  2. 配置选择参数

    let photoSelectOptions = {
      maxSelectNumber: 20,  // 最大选择数量
      MIMEType: picker.PhotoViewPicker.MIMEType.IMAGE,  // 限制为图片类型
    };
    
  3. 调用选择方法

    photoPicker.select(photoSelectOptions)
      .then(photoSelectResult => {
        // 处理选择的图片文件
        let uris = photoSelectResult.photoUris;
        // 执行上传逻辑
      })
      .catch(err => {
        console.error('PhotoPicker failed with err: ' + err);
      });
    

关键点说明:

  • maxSelectNumber参数控制批量选择的最大数量
  • 返回的photoUris数组包含所选图片的URI列表
  • 可通过文件管理接口读取文件内容进行上传

这种方式支持在系统的图片选择界面中多选图片,比单文件选择更高效。注意需要在module.json5中申请ohos.permission.READ_IMAGEVIDEO权限。

回到顶部