HarmonyOS鸿蒙Next中批量选择图片上传
HarmonyOS鸿蒙Next中批量选择图片上传 想要批量的选择大量的图片进行上传,批量选择,picker可以做到吗?
【问题剖析】
你好,选择器(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


【解决方案】
楼主可以自行配置选择器的属性以及图片选择限制
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个文件。
具体限制如下:
-
文档选择器 (DocumentViewPicker)
- 通过
DocumentSelectOptions的maxSelectNumber参数配置。 - 最大数量上限为 500 个文件。
- 有效值范围:1-500。
- 默认值为 500。
- 通过
-
图库选择器 (PhotoViewPicker)
- 通过
PhotoSelectOptions的maxSelectNumber参数配置。 - 最大数量上限为 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实现批量选择图片上传。具体步骤如下:
-
创建PhotoViewPicker实例:
let photoPicker = new picker.PhotoViewPicker(); -
配置选择参数:
let photoSelectOptions = { maxSelectNumber: 20, // 最大选择数量 MIMEType: picker.PhotoViewPicker.MIMEType.IMAGE, // 限制为图片类型 }; -
调用选择方法:
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权限。

