鸿蒙开发(十四)常用的picker(选择器)

655 阅读3分钟

我们开发的应用经常会有访问系统功能(如相机、麦克风等)或者用户数据(照片、视频、通讯录等)的需求场景,常规来讲我们需要先向用户申请对应的权限,才能进行相关操作,不仅麻烦而且还有隐私泄露的隐患,但HarmonyOS给我们提供了另外一种既便捷又安全的方式,那就是Picker。应用可以通过拉起系统Picker组件,由用户在Picker上选择对应的文件、照片、联系人的资源,来获取Picker的返回结果,应用只能看到用户选择让应用看到的内容而无法自由浏览某一类内容集合中的全部内容,这大大地提高了用户隐私的安全性。

  • DocumentViewPicker(文件选择器)

一、文件选择

1. 导入选择器模块和基础文件模块

image.png

2. 创建文件类型、文件选择选项实例

image.png

3. 创建文件选择器documentViewPicker实例,调用其select()方法进行文件选择并获得文件uri

image.png

4. 在组件中使用uri。完整演示代码如下:

import { picker, fileIo as fs } from '@kit.CoreFileKit'
import { common } from '@kit.AbilityKit';

const fileSelectionOpts = new picker.DocumentSelectOptions();
// 最大选择数量(可选)
fileSelectionOpts.maxSelectNumber = 5;
// 默认打开位置(可选)
fileSelectionOpts.defaultFilePathUri = 'file://docs/storage/';
// 文件类型['类型描述|类型后缀'](可选)同一类型有多个后缀时,用英文逗号分隔
fileSelectionOpts.fileSuffixFilters = ['文档(.png,.jpg)|.png,.jpg'];

@Entry
@Component
struct Index {
  @State uriList: string[] = [];

  async selectFiles() {
    // 获取组件的上下文
    let context = getContext(this) as common.Context;
    // 创建文件选择器实例
    const filePicker = new picker.DocumentViewPicker(context);
    this.uriList = await filePicker.select(fileSelectionOpts);
  }

  build() {
    RelativeContainer() {
      Button('点击选择图片')
        .id('button')
        .alignRules({
          top: { anchor: '__container__', align: VerticalAlign.Top },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .onClick(() => {
          this.selectFiles();
        })
      List() {
        ForEach(this.uriList, (uri: string, index) => {
          ListItem() {
            Column() {
              Text(uri)
              Image(uri).height('20%')
            }
          }
        })
      }
      .alignRules({
        top: { anchor: 'button', align: VerticalAlign.Bottom },
        middle: { anchor: '__container__', align: HorizontalAlign.Center }
      })
    }
    .height('100%')
    .width('100%')
  }
}

PixPin_2024-12-24_15-20-24.gif

二、文件保存

1. 创建文件类型、文件选保存选项实例

image.png

2. 创建文件选择器documentViewPicker实例,调用其save()方法进行文件保存并获得文件uri

image.png

3. 使用基础文件API,通过uri打开文件获得file,通过file.fd编辑文件,最后关闭文件

image.png

4. 完整演示代码如下:

import { picker, fileIo as fs } from '@kit.CoreFileKit'
import { common } from '@kit.AbilityKit';

// 创建文件管理器选项实例
const fileSaveOpts = new picker.DocumentSaveOptions();
// 保存文件名(可选)
fileSaveOpts.newFileNames = ["fileSaveTest.txt"];
// 文件类型['类型描述|类型后缀'](可选)同一类型有多个后缀时,用英文逗号分隔
fileSaveOpts.fileSuffixChoices = ['文档|.txt', '.pdf'];

@Entry
@Component
struct Index {
  // 要保存的内容
  @State textToSave:string = ''

  async saveFiles() {
    let context = getContext(this) as common.Context;
    // 创建文件选择器实例
    const filePicker = new picker.DocumentViewPicker(context);
    // 进行文件保存操作获得保存文件的uri
    let uris: string[] = await filePicker.save(fileSaveOpts);
    // 使用基础文件API的fs.openSync()接口,通过uri打开文件
    let file: fs.File = fs.openSync(uris[0], fs.OpenMode.READ_WRITE);
    // 使用fs.writeSync()接口,通过文件描述符(fd)对文件进行编辑,完成后关闭文件
    let writtenLen = fs.writeSync(file.fd, this.textToSave);
    fs.closeSync(file);
  }

  build() {
    RelativeContainer() {
      Button('点击保存内容')
        .id('button')
        .alignRules({
          top: { anchor: '__container__', align: VerticalAlign.Top },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .onClick(() => {
          this.saveFiles();
        })
      TextArea({placeholder:'请输入需要保存的内容', text:$$this.textToSave})
        .height(100)
        .margin({top:10})
        .alignRules({
          top: { anchor: 'button', align: VerticalAlign.Bottom },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}

PixPin_2024-12-24_17-52-53.gif

  • CameraPicker(相机选择器)

import { cameraPicker as picker } from '@kit.CameraKit';
import { camera } from '@kit.CameraKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

let mContext = getContext(this) as common.Context;

@Entry
@Component
struct Index {
  @State photoUri: string = ''

  async takePhoto() {
    try {
      let pickerProfile: picker.PickerProfile = {
        cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
      };
      let pickerResult: picker.PickerResult =
        await picker.pick(mContext, [picker.PickerMediaType.PHOTO, picker.PickerMediaType.VIDEO], pickerProfile);
      this.photoUri = pickerResult.resultUri;
    } catch (error) {
      let err = error as BusinessError;
      console.error(`the pick call failed. error code: ${err.code}`);
    }
  }

  build() {
    RelativeContainer() {
      Button('点击拍照')
        .onClick(() => {
          this.takePhoto();
        })
        .id('button')
        .alignRules({
          top:{anchor:'__container__', align:VerticalAlign.Top},
          middle:{anchor:'__container__', align:HorizontalAlign.Center}
        })
      Image(this.photoUri)
        .width('80%')
        .alt($r('app.media.startIcon'))
        .margin(30)
        .alignRules({
          top:{anchor:'button', align:VerticalAlign.Bottom},
          middle:{anchor:'__container__', align:HorizontalAlign.Center}
        })
    }
    .height('100%')
    .width('100%')
  }
}

PixPin_2024-12-24_20-25-56.gif

  • ContactPicker(联系人选择器)

import { contact as contactPicker } from '@kit.ContactsKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  @State contactInfo: string = ''

  async selectContacts() {
    contactPicker.selectContacts({
      isMultiSelect: false
    }, (err: BusinessError, data) => {
      if (err) {
        console.error(`selectContact callback: err->${JSON.stringify(err)}`);
        return;
      }
      this.contactInfo = JSON.stringify(data);
    });
  }

  build() {
    RelativeContainer() {
      Button('点击选择联系人')
        .onClick(() => {
          this.selectContacts();
        })
        .id('button')
        .alignRules({
          top: { anchor: '__container__', align: VerticalAlign.Top },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
      Text(this.contactInfo)
        .width('90%')
        .height('80%')
        .margin(30)
        .backgroundColor(Color.Gray)
        .alignRules({
          top: { anchor: 'button', align: VerticalAlign.Bottom },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}

PixPin_2024-12-24_20-43-17.gif