鸿蒙应用框架开发【选择并查看文档与媒体文件】 本地数据与文件

news2024/11/16 4:26:07

选择并查看文档与媒体文件

介绍

应用使用@ohos.file.picker、@ohos.file.fs等接口,实现了picker拉起文档编辑保存、拉起系统相册图片查看、拉起视频并播放的功能。

效果预览

1

使用说明:

  1. 在首页,应用显示查看最近打开文件功能的跳转按钮,点击后进入文件管理页面,可以通过最近页面,查看最近打开的文件。通过点击右上方的三个按钮,可以分别实现新建文档、选择图片或视频并打开预览、选择文档并打开的功能。
  2. 在查看文档界面,点击右上方左一按钮,可以实现当前文档另存为的功能;点击右上方中间的按钮,开启文档的编辑功能,textArea变成可编辑状态,用户输入数据后点击右上方第三个按钮,可以将当前文档内容进行保存操作(系统文档没有保存权限)。
  3. 在查看图片界面,picker拉起系统相册的图片,用户至多可选择三张图片查看,点击图片可以切换所显示的图片名及大小信息。
  4. 在查看视频界面,picker拉起系统相册的视频,用户至多可选择三个视频查看,点击视频播放并且可以显示的视频名及大小信息。

具体实现

  • 拉起picker选择文件、拉起picker保存文件、拉起picker选择图片或视频的功能封装在Index.ets,源码参考:[Index.ets]
/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { router } from '@kit.ArkUI';
import { picker } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import Logger from '../common/Logger';
import MediaFileUri from '../media/MediaFileUri';
import { Constants } from '../common/Constants';

const MAX_SELECT_NUM = 3; // 选择媒体文件的最大数目
const TAG = 'pickerIndex';

@Entry
@Component
struct Index {
  @State uri: string = 'Hello World';
  @State filename: string = '';
  @State sizeFile: number = 0;
  @State log: string = '';
  @State imageFlagCur: number = 0;
  @StorageLink('fileSizeList') fileSizeList: Array<number> = [];
  @StorageLink('fileNameList') fileNameList: Array<string> = [];
  @StorageLink('fileUriList') fileUriList: Array<string> = [];
  @StorageLink('imageNames') imageNames: Array<string> = [];
  mediaFileUri: MediaFileUri = new MediaFileUri();
  scroller: Scroller = new Scroller();
  authorizeBundleName: string = 'com.open.file.uri.demo';

  // 拉起picker选择文件
  async callFilePickerSelectFile(): Promise<void> {
    try {
      let DocumentSelectOptions = new picker.DocumentSelectOptions();
      let documentPicker = new picker.DocumentViewPicker();
      documentPicker.select(DocumentSelectOptions).then((DocumentSelectResult) => {
        Logger.info(TAG,
          'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + JSON.stringify(DocumentSelectResult));
        let editFlag = false;
        if (DocumentSelectResult !== null && DocumentSelectResult !== undefined) {
          DocumentSelectResult.forEach((value) => {
            this.uri = value;
            editFlag = true;
            Logger.info(TAG, `select file uri: ${this.uri}`);
          })
        }
        if (editFlag) {
          this.getFilenameByUri(this.uri);
        }
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'DocumentViewPicker.select failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'DocumentViewPicker failed with err: ' + JSON.stringify(err));
    }
  }

  // 拉起picker保存文件
  async callFilePickerSaveFile(): Promise<void> {
    try {
      let DocumentSaveOptions = new picker.DocumentSaveOptions();
      DocumentSaveOptions.newFileNames = ['MyDocument_01.txt'];
      let documentPicker = new picker.DocumentViewPicker();
      documentPicker.save(DocumentSaveOptions).then((DocumentSaveResult) => {
        Logger.info(TAG,
          'DocumentViewPicker.save successfully, DocumentSaveResult uri: ' + JSON.stringify(DocumentSaveResult));
        if (DocumentSaveResult !== null && DocumentSaveResult !== undefined) {
          this.uri = DocumentSaveResult[0];
          Logger.info(TAG, `save file uri: ${this.uri}`);
        }
        this.getFilenameByUri(this.uri);
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'DocumentViewPicker.save failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'DocumentViewPicker failed with err: ' + err);
    }
  }

  async getFilenameByUriForMedia(myUris: string[]) {
    router.pushUrl({
      url: 'pages/ViewMedia',
      params: {
        uris: myUris
      }
    }, router.RouterMode.Standard);
  }

  async getFilenameByUri(myUri: string): Promise<void> {
    // 获取文件名称
    this.filename = (myUri.split('/').pop()) as string;
    router.pushUrl({
      url: 'pages/EditFile',
      params: {
        fileName: this.filename,
        myUri: myUri
      }
    }, router.RouterMode.Standard);
  }

  // 拉起picker选择图片/视频
  async callFilePickerSelectImage(): Promise<void> {
    let array: string[];
    try {
      // 设置photoPicker的参数
      let PhotoSelectOptions = new picker.PhotoSelectOptions();
      // 过滤选择媒体文件类型
      PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;
      // 选择媒体文件的最大数目
      PhotoSelectOptions.maxSelectNumber = MAX_SELECT_NUM;
      let mediaFlag = false;
      // 使用图库选择器对象前,需要先创建PhotoViewPicker实例
      let photoPicker = new picker.PhotoViewPicker();
      photoPicker.select(PhotoSelectOptions).then((PhotoSelectResult) => {
        // 日志中记录成功信息
        Logger.info(TAG,
          'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(PhotoSelectResult));
        // 接口采用callback异步返回形式,返回PhotoSelectResult对象,故进行下一步操作前要先判断是否已经成功返回PhotoSelectResult对象了
        if (PhotoSelectResult !== null && PhotoSelectResult !== undefined) {
          // PhotoSelectResult为返回的结果集。
          // 其中包含Array<string>类型的photoUris,为返回图库选择后的媒体文件的uri数组;还包含boolean类型的isOriginalPhoto,指示返回图库选择后的媒体文件是否为原图。
          // 声明变量array,其取值为PhotoSelectResult中的数组。
          array = PhotoSelectResult['photoUris'];
          array.forEach((value) => {
            this.uri = value;
            mediaFlag = true;
            Logger.info(TAG, `select image/video uri: ${this.uri}`);
          })
        }
        if (mediaFlag) {
          this.getFilenameByUriForMedia(array);
        }
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'PhotoViewPicker.select failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'PhotoViewPicker failed with err: ' + err);
    }
  }

  aboutToDisappear(): void {
    this.fileNameList = [];
    this.fileSizeList = [];
    this.fileUriList = [];
  }

  onPageShow(): void {
    this.mediaFileUri.getAllFiles();
  }

  build() {
    Scroll(this.scroller) {
      Row() {
        Column() {
          Row() {
            Column() {
              Text($r('app.string.last_open'))
                .fontFamily('HarmonyHeiTi-Bold')
                .fontSize($r('app.float.text_font_size_30'))
                .fontWeight(Constants.TEXT_FONT_WIGHT)
                .textAlign(TextAlign.Start)
                .fontColor($r('app.color.text_font_color'))
                .lineHeight($r('app.float.first_line_height'))
                .width(Constants.SEVENTY_PERCENT)
                .height($r('app.float.first_line_height'))
            }
            .width(Constants.FIFTY_PERCENT)
            .margin({ left: Constants.PADDING_LEFT_RIGHT })
            .alignItems(HorizontalAlign.Start)

            Row() {
              Image($r('app.media.ic_saveas'))
                .width($r('app.float.image_size'))
                .height($r('app.float.image_size'))
                .margin({ right: Constants.IMAGE_MARGIN_RIGHT })
                .id('newFile')
                .onClick(() => {
                  this.callFilePickerSaveFile();
                })

              Image($r('app.media.ic_picture'))
                .width($r('app.float.image_size'))
                .height($r('app.float.image_size'))
                .id('picture')
                .margin({ right: Constants.IMAGE_MARGIN_RIGHT })
                .onClick(() => {
                  this.callFilePickerSelectImage();
                })

              Image($r('app.media.ic_folder'))
                .width($r('app.float.image_size'))
                .height($r('app.float.image_size'))
                .id('folder')
                .opacity(1)
                .margin({ right: Constants.MARGIN_RIGHT })
                .onClick(() => {
                  this.callFilePickerSelectFile();
                })
            }
            .justifyContent(FlexAlign.End)
            .padding({ right: Constants.PADDING_RIGHT })
            .width(Constants.FIFTY_PERCENT)
          }
          // 第一行结束
          .width(Constants.FULL_PERCENT)
          .height($r('app.float.first_line_height'))
          .margin({
            top: $r('app.float.first_line_margin_top'),
            left: $r('app.float.first_line_margin_left'),
            right: $r('app.float.first_line_margin_right'),
            bottom: $r('app.float.first_line_margin_bottom')
          })

          Row() {
            Text($r('app.string.view_last_open'))
              .fontSize($r('app.float.text_area_font_size'))
              .textAlign(TextAlign.Start)
              .lineHeight($r('app.float.line_height'))
              .margin({ left: $r('app.float.image_margin_left') })

            Blank()

            Image($r('app.media.right_arrow'))
              .height($r('app.float.text_height_19'))
              .width($r('app.float.image_width'))
              .margin({
                left: $r('app.float.image_margin_left'),
                right: $r('app.float.image_margin_left'),
                top: $r('app.float.image_margin_top'),
                bottom: $r('app.float.image_margin_top')
              })
          }
          .backgroundColor($r('app.color.start_window_background'))
          .width(Constants.FULL_PERCENT)
          .height($r('app.float.row_height'))
          .padding({
            top: $r('app.float.row_padding'),
            left: $r('app.float.margin_padding_12'),
            right: $r('app.float.margin_padding_12')
          })
          .onClick(() => {
            this.callFilePickerSelectFile();
          })

          Column() {
            List({ space: Constants.LIST_SPACE, initialIndex: 0 }) {
              ForEach(this.fileNameList, (item: string, index?: number) => {
                ListItem() {
                  Row() {
                    Image($r('app.media.ic_docs'))
                      .width(Constants.IMAGE_WIDTH)
                      .height($r('app.float.line_height'))
                      .margin({
                        left: $r('app.float.margin_left'),
                        right: $r('app.float.margin_right')
                      })

                    Text(item)
                      .fontSize($r('app.float.text_area_font_size'))
                      .fontFamily('HarmonyHeiTi-Medium')
                      .fontColor($r('app.color.text_font_color'))
                      .lineHeight($r('app.float.line_height'))
                      .textAlign(TextAlign.Start)
                      .margin({ right: $r('app.float.padding_left_right') })
                      .width(Constants.SIXTY_FOUR_PERCENT)
                    if (index !== undefined) {
                      Text('Size: ' + JSON.stringify(this.fileSizeList[index]) + 'B')
                        .fontSize($r('app.float.text_font_size_14'))
                        .fontFamily('HarmonyHeiTi-Medium')
                        .lineHeight($r('app.float.text_height_19'))
                        .fontColor($r('app.color.text_font_color'))
                        .textAlign(TextAlign.End)
                        .opacity(Constants.TEXT_OPACITY)
                        .width(Constants.TEXT_WIDTH)
                        .margin({ right: $r('app.float.margin_padding_12') })
                    }
                  }
                  .id('fileItem' + (index !== undefined ? index : ""))
                  .borderRadius(Constants.BORDER_RADIUS)
                  .width(Constants.FULL_PERCENT)
                  .height($r('app.float.row_height_64'))
                  .padding({ right: $r('app.float.margin_padding_12') })
                  .backgroundColor($r('app.color.start_window_background'))
                }
                .onClick(() => {
                  Logger.info(TAG, 'fileAsset.displayName fileName item: ' + item);
                  if (index !== undefined) {
                    router.pushUrl({
                      url: 'pages/EditFile',
                      params: {
                        fileName: item,
                        myUri: this.fileUriList[index]
                      }
                    }, router.RouterMode.Standard);
                  }
                })
              }, (item: string) => item)
            }
            .listDirection(Axis.Vertical) // 排列方向
            .id('indexList')
            .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
            .scrollBar(BarState.Auto)
            .alignListItem(ListItemAlign.Center)
            .margin({
              top: Constants.LIST_MARGIN_TOP,
              left: $r('app.float.margin_padding_12'),
              right: $r('app.float.margin_padding_12')
            })
          }
          .height(Constants.FULL_PERCENT)
          .width(Constants.FULL_PERCENT)
        }
        .alignItems(HorizontalAlign.Center)
        .width(Constants.FULL_PERCENT)
        .height(Constants.FULL_PERCENT)
        .backgroundColor($r('app.color.common_background'))
      }
      .height(Constants.FULL_PERCENT)
    }
  }
}
  • 使用new picker.DocumentViewPicker来创建文件picker实例,使用documentPicker.select来拉起picker选择文件,使用documentPicker.save来拉起picker保存文件,接口参考:@ohos.file.picker

  • 使用new picker.PhotoViewPicker来创建图库picker实例,使用photoPicker.select来拉起picker选择图片或视频,接口参考:@ohos.file.picker

  • 编辑文件并保存的功能封装在EditFile.ets,源码参考:[EditFile.ets]

/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { promptAction, router } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { fileIo, picker } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import MediaFileUri from '../media/MediaFileUri';
import Logger from '../common/Logger';
import { terminateSelf } from '../utils/utils';
import { Constants } from '../common/Constants';

const TAG = 'EditFile: ';
let storage = LocalStorage.getShared();
const OPACITY_VALUE = 0.6; // 透明度

interface myParams extends Object {
  myUri: string,
  fileName: string
};

@Entry(storage)
@Component
struct EditFile {
  @LocalStorageLink('loadFlag') loadFlag: Boolean = false;
  @LocalStorageLink('loadFileSize') loadFileSize: number = 0;
  @LocalStorageLink('loadFileName') loadFileName: string = '';
  @LocalStorageLink('loadFileContent') loadFileContent: string = '';
  @LocalStorageLink('loadUri') loadUri: string = '';
  @LocalStorageLink('fd') loadFd: number = 0;
  @StorageLink('editable') editable: Boolean = false;
  @StorageLink('myFileSize') myFileSize: number = 0;
  @StorageLink('myFileContent') myFileContent: string = '';
  @State myContext: Context = getContext(this) as common.UIAbilityContext;
  @State myUri: string = '';
  @State opacityValue: number = OPACITY_VALUE;
  @State uriSave: string = '';
  @State myFileName: string = '';
  public fileContentFlag: boolean = false;
  newFileContent: string = '';
  scroller: Scroller = new Scroller();
  controller: TextAreaController = new TextAreaController();
  mediaFileUri: MediaFileUri = new MediaFileUri();

  getFileInfo(): void {
    if (this.loadFlag) {
      this.myFileName = this.loadFileName;
      this.myFileContent = this.loadFileContent;
      this.myFileSize = this.loadFileSize;
      this.myUri = this.loadUri;
      Logger.info(TAG, 'The count of getFileInfo is myFileContent ' + this.myFileContent);
    } else {
      this.myUri = (router.getParams() as myParams).myUri;
      this.myFileName = (router.getParams() as myParams).fileName;
      this.myFileContent = this.mediaFileUri.readFileContent(this.myUri);
      this.myFileSize = this.mediaFileUri.myGetFileSize(this.myUri, fileIo.OpenMode.READ_ONLY);
      Logger.info(TAG, 'The count of getFileInfo is myFileName is: ' + this.myFileName);
      Logger.info(TAG, 'The count of getFileInfo is myFileContent ' + this.myFileContent);
      Logger.info(TAG, 'The count of getFileInfo is myFileSize ' + this.myFileSize);
    }
    AppStorage.setOrCreate('myFileContent', this.myFileContent);
    AppStorage.setOrCreate('myFileSize', this.myFileSize);
  }

  async writeContentForSaveAsFile(myUri: string, wrFlag: Boolean = false): Promise<void> {
    if (wrFlag) {
      Logger.info(TAG, 'fileAsset.displayName wrFlag is true');
      Logger.info(TAG, 'fileAsset.displayName wrFlag myFileContent :' + this.myFileContent);
      this.mediaFileUri.writeFileContent(myUri, this.myFileContent);
    }
  }

  // 拉起picker保存文件
  async callFilePickerSaveFile(): Promise<void> {
    try {
      let DocumentSaveOptions = new picker.DocumentSaveOptions();
      DocumentSaveOptions.newFileNames = ['MyDocument_01.txt'];
      let documentPicker = new picker.DocumentViewPicker();
      documentPicker.save(DocumentSaveOptions).then((DocumentSaveResult) => {
        Logger.info(TAG,
          'DocumentViewPicker.save successfully, DocumentSaveResult uri: ' + JSON.stringify(DocumentSaveResult));
        if (DocumentSaveResult !== null && DocumentSaveResult !== undefined) {
          this.uriSave = DocumentSaveResult[0];
          Logger.info(TAG, `save callFilePickerSaveFile file this.uriSave: ${this.uriSave}`);
        }
        Logger.info(TAG, 'fileAsset.displayName wrFlag myFileContent :' + this.myFileContent);
        // 用 medialibrary 重新获取uri,进行写入操作
        this.writeContentForSaveAsFile(this.uriSave, true);
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'DocumentViewPicker.save failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'DocumentViewPicker failed with err: ' + err);
    }
  }

  onPageShow(): void {
    this.getFileInfo();
    this.editable = false;
  }

  build() {
    Column() {
      // 顶部的行容器
      Row() {
        // 后退箭头
        Row() {
          Image($r('app.media.ic_back'))
            .focusable(true)
            .focusOnTouch(true)
            .id('backIndex')
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .align(Alignment.Start)
            .onClick(() => {
              if (this.loadFlag) {
                Logger.info(TAG, 'end page');
                let context = getContext(this);
                terminateSelf(context);
              } else {
                router.back();
              }
            })
        }
        .margin({ left: Constants.MARGIN_LEFT })

        // 文件名及信息
        Column() {
          Row() {
            Text(this.myFileName)
              .focusable(true)
              .focusOnTouch(true)
              .fontSize($r('app.float.text_font_size'))
              .fontFamily('HarmonyHeiTi-Bold')
              .fontColor($r('app.color.text_font_color'))
              .textAlign(TextAlign.Start)
              .fontWeight(Constants.TEXT_FONT_WIGHT)
              .lineHeight(Constants.TEXT_LINE_HEIGHT)
              .maxLines(1)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
          }
          .width(Constants.FULL_PERCENT)
          .align(Alignment.Start)
          .margin({
            left: Constants.MARGIN_LEFT,
            top: Constants.MARGIN_TOP,
            bottom: Constants.MARGIN_ZERO_POINT_THREE_PERCENT
          })

          Row() {
            Text('size: ' + JSON.stringify(this.myFileSize) + 'B')
              .focusable(true)
              .focusOnTouch(true)
              .opacity(Constants.TEXT_OPACITY)
              .fontFamily('HarmonyHeiTi')
              .fontSize($r('app.float.text_font_size_14'))
              .fontColor($r('app.color.text_font_color'))
              .textAlign(TextAlign.Start)
              .lineHeight(Constants.TEXT_LINE_HEIGHT_19)
              .fontWeight(Constants.TEXT_FONT_WIGHT_400)
          }
          .width(Constants.FULL_PERCENT)
          .margin({
            left: Constants.MARGIN_LEFT,
            top: Constants.MARGIN_ZERO_POINT_THREE_PERCENT,
            bottom: Constants.MARGIN_ZERO_POINT_FIVE_PERCENT
          })
          .align(Alignment.Start)
        }
        .width(Constants.FORTY_FIVE_PERCENT)
        .margin({ left: Constants.MARGIN_LEFT })

        // 右边三个图标
        Row() {
          Image($r('app.media.ic_saveas'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .id('saveAs')
            .margin({ right: Constants.IMAGE_MARGIN_RIGHT })
            .onClick(() => {
              this.callFilePickerSaveFile();
            })
            .visibility(this.loadFlag ? Visibility.Hidden : Visibility.Visible)

          Image($r('app.media.ic_writting'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .id('editable')
            .margin({ right: Constants.IMAGE_MARGIN_RIGHT })
            .onClick(() => {
              this.editable = true;
              AppStorage.setOrCreate('editable', this.editable);
              Logger.info(TAG, 'EditFile caretPosition length = ' + this.myFileContent.length);
              this.controller.caretPosition(this.myFileContent.length);
              promptAction.showToast({ message: $r('app.string.editable') });
            })

          Image($r('app.media.ic_save'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .id('save')
            .margin({ right: Constants.MARGIN_LEFT })
            .onClick(() => {
              if (this.fileContentFlag) {
                let flage: boolean = true;
                this.myFileContent = this.newFileContent;
                AppStorage.setOrCreate('myFileContent', this.myFileContent);
                Logger.info(TAG, 'save onClick myFileContent is: ' + this.myFileContent);
                Logger.info(TAG, 'save onClick this.loadUri: ' + this.loadUri);
                if (this.loadFlag) {
                  let file = fileIo.openSync(this.loadUri,
                    fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.TRUNC);
                  Logger.info(TAG, 'save onClick file.fd is: ' + file.fd);
                  fileIo.write(file.fd, this.myFileContent).then((writeLen) => {
                    Logger.info(TAG, 'write data to file succeed and size is:' + writeLen);
                    this.myFileSize = fileIo.statSync(file.fd).size;
                    AppStorage.setOrCreate('myFileSize', this.myFileSize);
                    Logger.info(TAG, 'save onClick this.myFileSize ' + this.myFileSize);
                  }).catch((err: BusinessError) => {
                    Logger.info(TAG, 'write data to file failed with error:' + JSON.stringify(err));
                  });
                  fileIo.closeSync(file);
                } else {
                  try {
                    let file = fileIo.openSync(this.myUri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.TRUNC);
                    let writeLen = fileIo.writeSync(file.fd, this.myFileContent);
                    this.myFileSize = fileIo.statSync(file.fd).size;
                    AppStorage.setOrCreate('myFileSize', this.myFileSize);
                    Logger.info(TAG, 'write data to file succeed and size is:' + writeLen);
                    fileIo.closeSync(file);
                  } catch (err) {
                    flage = false;
                    Logger.info(`save data to file failed with error:
                      ${JSON.stringify(err)}: ${JSON.stringify(err?.message)}`);
                    promptAction.showToast({
                      message: Constants.SHOW_TOAST_MESSAGE,
                      duration: 6500
                    })
                  }
                }
                if (flage) {
                  this.editable = false;
                  AppStorage.setOrCreate('editable', this.editable);
                  promptAction.showToast({ message: $r('app.string.saved') });
                }
              }
            })
        }
        .height(Constants.FIFTY_PERCENT)
        .width(Constants.THIRTY_SEVEN_POINT_TWO)
        .padding({ right: Constants.MARGIN_ZERO_POINT_FIVE_PERCENT })
        .justifyContent(FlexAlign.End)
      }
      .height(Constants.SEVEN_POINT_FOUR)
      .width(Constants.FULL_PERCENT)

      Scroll(this.scroller) {
        // TextArea的行容器
        Row() {
          TextArea({
            text: this.newFileContent ? this.newFileContent : this.myFileContent,
            placeholder: Constants.TEXT_AREA_PLACEHOLDER,
            controller: this.controller
          })
            .id('textArea')
            .fontSize($r('app.float.text_area_font_size'))
            .fontColor($r('app.color.text_font_color'))
            .opacity(this.opacityValue)
            .fontWeight(Constants.TEXT_FONT_WIGHT_400)
            .align(Alignment.TopStart)
            .textAlign(TextAlign.Start)
            .backgroundColor($r('app.color.common_background'))
            .fontFamily('HarmonyHeiTi')
            .padding({
              top: $r('app.float.padding_top_bottom'),
              right: $r('app.float.padding_left_right'),
              left: $r('app.float.padding_left_right'),
              bottom: $r('app.float.padding_top_bottom')
            })
            .focusable(this.editable ? true : false)
            .focusOnTouch(true)
            .defaultFocus(false)
            .onFocus(() => {
              this.opacityValue = 1;
            })
            .onBlur(() => {
              this.opacityValue = OPACITY_VALUE;
            })
            .onChange((value: string) => {
              this.newFileContent = value;
              this.fileContentFlag = true;
            })
        }
        .padding({
          top: Constants.PADDING_TOP,
          left: Constants.PADDING_LEFT_RIGHT,
          right: Constants.PADDING_LEFT_RIGHT
        })
      }
    }
    .backgroundColor($r('app.color.common_background'))
    .height(Constants.FULL_PERCENT)
  }
}
  • 使用fs.openSync、fs.writeSync、fs.readSync、fs.closeSync分别用来打开文件、写文件、读文件、关闭文件,接口参考:@ohos.file.fs

  • 拉起图片或视频并查看的功能封装在ViewMedia.ets,源码参考:[ViewMedia.ets]

/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { router } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { fileIo, picker } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import MediaFileUri from '../media/MediaFileUri';
import Logger from '../common/Logger';
import { Constants } from '../common/Constants';

const TAG = 'ViewMedia';

interface myParams extends Object {
  uris: string[]
};

@Entry
@Component
struct ViewMedia {
  @State myContext: Context = getContext(this) as common.UIAbilityContext;
  @State myFileSizes: number[] = [];
  @State myFileNames: string[] = [];
  @State myFileTypes: number[] = [];
  @StorageLink('myFileName') myFileName: string = '';
  @StorageLink('myFileSize') myFileSize: number = 0;
  @State myUris: string[] = (router.getParams() as myParams).uris;
  @State uri: string = 'Hello World';
  @StorageLink('showPauses') showPauses: Array<number> = [];
  mediaFileUri: MediaFileUri = new MediaFileUri();
  scroller: Scroller = new Scroller();
  currentUri: string = '';
  controllers: Array<VideoController> = [];

  // 拉起picker保存图片/视频
  async callFilePickerSaveImageVideo(): Promise<void> {
    try {
      let PhotoSaveOptions = new picker.PhotoSaveOptions();
      PhotoSaveOptions.newFileNames = ['PhotoViewPicker01.jpg', 'PhotoViewPicker01.mp4'];
      let photoPicker = new picker.PhotoViewPicker();
      photoPicker.save(PhotoSaveOptions).then((PhotoSaveResult) => {
        Logger.info(TAG, 'PhotoViewPicker.save successfully, PhotoSaveResult uri: ' + JSON.stringify(PhotoSaveResult));
        if (PhotoSaveResult !== null && PhotoSaveResult !== undefined) {
          PhotoSaveResult.forEach((value: string) => {
            this.uri = value
            Logger.info(TAG, `save image/video uri: ${this.uri}`);
          })
        }
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'PhotoViewPicker.save failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'PhotoViewPicker failed with err: ' + err);
    }
  }

  onPageShow() {
    this.getImagesInfo();
    this.myFileName = this.myFileNames[0];
    this.myFileSize = this.myFileSizes[0];
    Logger.info(TAG, 'onPageShow getFilenameByUriForMedia this.myFileName ' + this.myFileName);
    Logger.info(TAG, 'onPageShow getFilenameByUriForMedia begin ' + this.myFileSize);
    AppStorage.setOrCreate('myFileName', this.myFileName);
    AppStorage.setOrCreate('myFileSize', this.myFileSize);
  }

  async getMediaNameByUri(myUri: string, index: number) {
    Logger.info(TAG, 'getMediaNameByUri getFilenameByUriForMedia begin');
    this.myFileName = (myUri.split('/').pop()) as string;
    this.myFileNames[index] = this.myFileName;
  }

  getImagesInfo() {
    for (let index = 0; index < this.myUris.length; index++) {
      Logger.info(TAG, 'getFilenameByUriForMedia  getImagesInfo  index: ' + index);
      this.controllers[index] = new VideoController();
      this.getMediaNameByUri(this.myUris[index], index);
      this.myFileSizes[index] = this.mediaFileUri.myGetFileSize(this.myUris[index], fileIo.OpenMode.READ_ONLY);
      Logger.info(TAG, 'getFilenameByUriForMedia  getVideosInfo  this.myFileNames[index]: '
        + this.myFileNames[index] + ' index ' + index);
      Logger.info(TAG, 'getFilenameByUriForMedia getVideosInfo this.myFileSizes[index]' + this.myFileSizes[index]);
      Logger.info(TAG, 'getFilenameByUriForMedia getVideosInfo this.myFileTypes[index] cc' + this.myFileTypes[index]);
    }
  }

  build() {
    Column() {
      // 顶部的行容器
      Row() {
        // 后退箭头
        Row() {
          Image($r('app.media.ic_back'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .align(Alignment.Start)
            .id('back2Index')
            .onClick(() => {
              router.back();
            })
        }
        .width(Constants.BACK_WIDTH)
        .padding({ left: Constants.BACK_PADDING_LEFT })

        // 文件名及信息
        Column() {
          Row() {
            Text(this.myFileName)
              .focusable(true)
              .focusOnTouch(true)
              .fontSize($r('app.float.text_font_size'))
              .fontFamily('HarmonyHeiTi-Bold')
              .fontColor($r('app.color.text_font_color'))
              .textAlign(TextAlign.Start)
              .fontWeight(Constants.TEXT_FONT_WIGHT)
              .lineHeight($r('app.float.text_height'))
              .maxLines(1)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
          }
          .width(Constants.FULL_PERCENT)
          .align(Alignment.Start)
          .margin({
            top: Constants.MARGIN_TOP,
            bottom: Constants.MARGIN_ZERO_POINT_THREE_PERCENT
          })

          Row() {
            Text('size: ' + JSON.stringify(this.myFileSize) + 'B')
              .focusable(true)
              .focusOnTouch(true)
              .opacity(Constants.TEXT_OPACITY)
              .fontFamily('HarmonyHeiTi')
              .fontSize($r('app.float.text_font_size_14'))
              .fontColor($r('app.color.text_font_color'))
              .textAlign(TextAlign.Start)
              .lineHeight($r('app.float.text_height_19'))
              .fontWeight(Constants.TEXT_FONT_WIGHT_400)
          }
          .width(Constants.FULL_PERCENT)
          .margin({
            top: Constants.MARGIN_ZERO_POINT_THREE_PERCENT,
            bottom: Constants.MARGIN_ZERO_POINT_FIVE_PERCENT
          })
          .align(Alignment.Start)
        }
        .width(Constants.FORTY_FIVE_PERCENT)
        .margin({ left: Constants.MARGIN_LEFT })

        // 右边一个图标,另存为
        Row() {
          Image($r('app.media.ic_saveas'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .visibility(Visibility.Hidden)
        }
        .height(Constants.FULL_PERCENT)
        .width(Constants.THIRTY_SEVEN_POINT_TWO)
        .padding({ right: Constants.BACK_PADDING_LEFT })
        .justifyContent(FlexAlign.End)
      }
      .height(Constants.SEVEN_POINT_FOUR)
      .width(Constants.FULL_PERCENT)

      Scroll(this.scroller) {
        // 显示媒体文件的容器
        Column() {
          List({ space: Constants.LIST_SPACE_20, initialIndex: 0 }) {
            ForEach(this.myUris, (uri: string, index?: number) => {
              ListItem() {
                Column() {
                  Image(uri)
                    .borderRadius(Constants.BORDER_RADIUS)
                    .onClick(() => {
                      if (index !== undefined) {
                        this.myFileSize = this.myFileSizes[index];
                        this.myFileName = this.myFileNames[index];
                      }
                      AppStorage.setOrCreate('myFileName', this.myFileName);
                      AppStorage.setOrCreate('myFileSize', this.myFileSize);
                      Logger.info(TAG, 'Image onClick myFileName is ' + this.myFileName);
                      Logger.info(TAG, 'Image onClick myFileName is ' + this.myFileSize);
                    })
                  if (index !== undefined) {
                    Stack({ alignContent: Alignment.Center }) {
                      Video({
                        src: uri,
                        controller: this.controllers[index]
                      })
                        .autoPlay(false)
                        .controls(true)
                        .borderRadius(Constants.BORDER_RADIUS)

                      Image($r('app.media.ic_PAUSE'))
                        .width($r('app.float.image_size'))
                        .height($r('app.float.image_size'))
                        .onClick(() => {
                          this.controllers[index].start();
                          this.showPauses[index] = 0;
                        })
                    }
                    .onClick(() => {
                      this.myFileSize = this.myFileSizes[index];
                      this.myFileName = this.myFileNames[index];

                      AppStorage.setOrCreate('myFileName', this.myFileName);
                      AppStorage.setOrCreate('myFileSize', this.myFileSize);
                    })
                  }
                }
                .height(Constants.FULL_PERCENT)
              }
              .height(Constants.TWENTY_FIVE_PERCENT)
            }, (item: string) => item)
          }
          .id('picScroller')
          .scrollBar(BarState.Auto)
        }
      }
      .padding({
        top: Constants.ONE_POINT_FIVE_PERCENT,
        left: Constants.PADDING_LEFT_RIGHT,
        right: Constants.PADDING_LEFT_RIGHT
      })
    }
    .backgroundColor($r('app.color.common_background'))
    .height(Constants.FULL_PERCENT)
  }
}

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

在这里插入图片描述

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GD32手把手教你移植FlashDB(片外Flash) -- 3.FlashDB使用

GD32手把手教你移植FlashDB(片外Flash) – 1.FlashDB-sfud移植 GD32手把手教你移植FlashDB(片外Flash) – 2.FlashDB移植 GD32手把手教你移植FlashDB(片外Flash) – 3.FlashDB使用 示例代码: https://gitee.com/ljmRD/GD32F427_FlashDB 3.FlashDB使用 main() /*************…

浅谈取样器之SSH Command

浅谈取样器之SSH Command JMeter的SSH Command取样器是一个强大的功能&#xff0c;允许用户在JMeter测试计划中执行远程SSH命令。这对于需要与Linux/Unix服务器交互以执行系统命令、脚本或者进行性能测试验证的场景尤为有用。通过这个取样器&#xff0c;您可以集成服务器端操作…

Linux中进程通信之信号

信号 信号通信&#xff0c;其实就是内核向用户空间进程发送信号&#xff0c;只有内核才能发信号&#xff0c;用户空间进程不能发送信号。 关于信号指令的查看&#xff1a;kill -l 例如我们之前使用的kill -9 pid用于杀死一个进程 使用一个死循环 成功发送kill -9指令&#x…

对于AI大模型发展态势的几点认识

本期内容从AI大模型产业的视角出发&#xff0c;全面审视该产业的发展现状&#xff0c;深入剖析其成长轨迹和未来趋势&#xff0c;旨在为人工智能产业的参与者提供一个全面的视角&#xff0c;更好地理解AI大模型产业的复杂性、动态性和潜力&#xff0c;以及如何在这个快速变化的…

Ruoyi 快速开发平台

Ruoyi 快速开发平台 一、官网二、准备工作2.1 环境要求2.2 必要配置 三、运行系统3.1 后端运行3.2 前端安装及运行 四、自定义开发4.1 新增业务模块4.2 代码生成4.2.1 创建菜单4.2.2 后端代码4.2.3 前端代码 一、官网 链接: 前后端分离版本 回到目录 二、准备工作 2.1 环境要…

UDP服务器端bind失败问题

本人使用microchip芯片开发&#xff0c;使用UDP虚拟机通讯&#xff0c;经常提示bind失败&#xff0c;返回-1&#xff0c;尝试了以前UDP作为客户端使用时正常&#xff0c;故硬件链路没问题。 一、可能有几个原因&#xff1a; 端口实际上被占用&#xff1a;最明显的原因是端口真…

基于入侵野草算法的KNN分类优化matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 入侵野草算法 4.2 K近邻分类器&#xff08;KNN&#xff09; 4.3 基于IWO的KNN分类优化 5.完整程序 1.程序功能描述 基于入侵野草算法的KNN分类优化。其中&#xff0c;入侵野草算法是一…

GEE APP:利用谷歌地球引擎实现更有效的草原管理:决策支持应用视角

简介 草原占地球表面和农田的很大一部分,对人类福祉和畜牧业至关重要。由于牧区基础设施不发达、通信不畅,牧民和草原管理部门在有效控制牧民放牧行为和草原利用方面面临挑战。要解决这一问题,促进草原的可持续利用并保护其生态系统服务,就需要基于云的放牧管理和决策支持…

C++初阶大总结

目录 一.命名空间 1.命名空间定义 2.命名空间使用 二.C++输入&输出 三.缺省参数 四. 函数重载 五.引用 1.常引用 2.传值、传引用效率比较 3.引用和指针的区别 4.引用和指针的不同点: 小知识点: 六.内联函数 七.auto关键字(C++11) 1.auto的使用细则 八.基于…

24暑假算法刷题 | Day23 | LeetCode 39. 组合总和,40. 组合总和 II,131. 分割回文串

目录 39. 组合总和题目描述题解 40. 组合总和 II题目描述题解 131. 分割回文串题目描述题解 39. 组合总和 点此跳转题目链接 题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有…

Dolphinscheduler 3.2.1bug记录

问题1&#xff1a;分页只展示首页 解决方案&#xff1a; [Bug][API] list paging missing totalpage by Gallardot Pull Request #15619 apache/dolphinscheduler GitHub 问题2:Hive 数据源连接失败 解决方案&#xff1a;修改源码&#xff1a;HiveDataSourceProcessor.cla…

A Survey on Multimodal Large Language Models(from gpt-4o)

目录 A Survey on Multimodal Large Language Models1. INTRODUCTION2. ARCHITECTURE2.1 Modality encoder2.2 Pre-trained LLM2.3 Modality interface 3. TRAINING STRATEGY AND DATA3.1 Pre-training3.1.1 Training Detail3.1.2 Data 3.2 Instruction-tuning3.2.1 Introducti…

Linux下文件编译器-GCC/G++

前言 本文介绍了c/c的编译过程以及gcc/g的时使用 一.c/c翻译的本质&#xff1a;将高级语言翻译成二进制 1&#xff09;程序翻译过程&#xff1a; &#xff08;1&#xff09;预处理&#xff08;头文件展开、宏替换、去注释、条件编译&#xff09;还是C语言代码 ​ …

hash表如何形成,hash函数如何计算,什么是hash冲突 如何解决 ,Golang map的底层原理及扩容机制

散列表 散列表&#xff08;hash表&#xff09;:根据给定的关键字来计算出关键字在表中的地址的数据结构。也就是说&#xff0c;散列表建立了关键字和 存储地址之间的一种直接映射关系。 问题&#xff1a;如何建立映射管血 散列函数:一个把查找表中的关键字映射成该关键字对应…

平移、旋转、缩放和媒体

一、平移 1.1translate&#xff08;&#xff09;函数 做转换工作可以用translate()函数&#xff0c;这个函数可以改变坐标系。通过改变默认的坐标系&#xff0c;我们可以创建不同的转换方式&#xff0c;包括平移、旋转和缩放。 1.2平移位置案例 案例代码如图1 图1 保存运行如…

【大一公共课】C语言+python语言入门对比+思维导图

C 和 Python 入门教程对比 一、引言 C 语言和 Python 语言都是在编程领域中广泛使用的语言&#xff0c;但它们在语法、应用场景和学习难度上有很大的不同。本教程将对 C 和 Python 的入门知识进行对比&#xff0c;帮助您更好地理解和选择适合自己的编程语言。 二、C 语言入门 …

python爬取某财富网

过程&#xff1a; 点击底部的第3页&#xff0c;第5页&#xff0c;网页刷新了&#xff0c;但是顶部的url地址没有变。那么就是 动态加载&#xff0c; 就是 XHR. 直接请求api. 实验代码如下: import requestsheaders {"User-Agent": "Mozilla/5.0 (Windows NT…

LLM大模型:2024工业AI大模型发展分析

一、大模型为工业智能化发展带来新机遇 1.1. 大模型开启人工智能应用新时代 大模型引领人工智能技术创新和应用。 自 1956 年达特茅斯会议&#xff08;Dartmouth Conference&#xff09;提出人工智能的概念以来&#xff0c;人工智能技术经历了多个发展高峰和低谷。在这一长期的…

《深入浅出WPF》学习笔记一.解析WPF程序

《深入浅出WPF》学习笔记一.解析WPF程序 visual studio帮助我们做了那些事情 引用文件 输出文件类型 按照最原始的方式&#xff0c;我们需要手动打开编译器命令行&#xff0c;使用命令引用类库将代码编译成目标文件。 visual studio会根据我们选择的项目模板&#xff0c;自动…

Java学习Day19:基础篇9

包 final 权限修饰符 代码块 静态代码块在Java中是一个重要的特性&#xff0c;它主要用于类的初始化操作&#xff0c;并且随着类的加载而执行&#xff0c;且只执行一次。静态代码块的实践应用广泛&#xff0c;以下是几个主要的应用场景&#xff1a; 1. 初始化静态变量 静态代…