HarmonyOS 如何实现加载组件封装单独调用?

HarmonyOS Next开发过程中, 加载组件使用频率高, 但目前只能在Component类里面创建及调用, 代码冗余, 请问如何实现此组件抽取封装.

实现类似如下效果(以下是伪代码):

import YksLoadingView from '../components/YksLoadingView';

class LoadingUtils {

  dialogController:CustomDialogController = new CustomDialogController({
    builder: YksLoadingView(),
    //是否允许点击遮障层退出。
    autoCancel: false,
    customStyle: true,
    //弹窗在竖直方向上的对齐方式。
    alignment:DialogAlignment.Center
  });

  showLoading() {
    this.dialogController.open()
  }

  hideLoading() {
    this.dialogController.close()
  }

}

export default new LoadingUtils
阅读 491
1 个回答

参考以下demo:

@Entry
@Component
export struct LoadingPage {
  @State message: string = 'Hello World';

  wTRHud:WTRHUD = new WTRHUD()


  build() {
    NavDestination() {
      Column({ space: 30 }) {
        Button('Toast提示有文案')
          .onClick(() => {
            this.wTRHud.showLoading({msg:'加载中'})
          })
        Button('Toast提示无文案')
          .onClick(() => {
            this.wTRHud.showLoading()
          })
        Button('信息提示')
          .onClick(() => {
            this.wTRHud.showInfo("信息提示")
          })
        Button('成功')
          .onClick(() => {
            this.wTRHud.showSuccess("操作成功")
          })
        Button('失败')
          .onClick(() => {
            this.wTRHud.showError("网络错误")
          })
        Button('Toast消失')
          .onClick(() => {
            this.wTRHud.hide()
          })
      }
    }
    .height('100%')
    .width('100%')
  }
}

/*
 * 使用方法:
 * 信息提示:new WTRHUD().showInfo("信息提示")
 * 加载动画:new WTRHUD().showLoading()
 * 成功显示:new WTRHUD().showSuccess("操作成功")
 * 失败显示:new WTRHUD().showError("网络错误")
 *
 * 另一种方式:
 *  new WTRHUD().showInfo({
 *    msg: "信息提示",
 *    alignment: DialogAlignment.Bottom
 *  })
 *
 * 取消:new WTRHUD().hide()
 */

export class WTRHUDTime {
  //显示时间为 baseTime+msg.length * wordTime
  static baseTime: number = 400 //消息显示基本时间
  static wordTime: number = 90 //每个字增加显示的时间

  //最终显示时间为上面计算结果限制到最短与最长之间
  static minTime: number = 1600 //最短显示时间
  static maxTime: number = 4200 //最长显示时间
}

export enum WTRHUDType {
  Loading = 0,
  Info,
  Success,
  Error,
  Length
}

interface WTRHUDParam {
  msg: string,
  cancelCallBack?: () => void,
  alignment?: DialogAlignment,
  offset?: Offset,
  showInSubWindow?: boolean,
  isModal?: boolean,
  tmpHUDNum?: number, //缓存HUD的数量,用于多层返回HUD不显示情况
}

@CustomDialog
struct _WTRHUD {
  controller: CustomDialogController
  close: () => void = () => {
  }
  type: WTRHUDType = WTRHUDType.Loading
  image: ResourceStr | undefined = undefined
  @State angle: number = 0
  @State msg: string = ""

  aboutToAppear() {
    if (this.type == WTRHUDType.Loading) {
      setTimeout(() => {
        this.angle = 360
      }, 100)
    }
  }

  build() {
    Column() {
      if (this.type == WTRHUDType.Loading) {
        Row()
          .width(px2vp(200))
          .height(px2vp(200))
          .sweepGradient({
            center: [px2vp(100), px2vp(100)],
            rotation: 280,
            start: 0,
            end: 360,
            colors:
            [['rgba(255, 255, 255, 0.0)', 0.0], ['rgba(255, 255, 255, 0.0)', 0.18], ['rgba(255, 255, 255, 1.0)', 1.0]]
          })
          .clip(new Path({
            width: 100, height: 100, commands:
            `
M100 10
A90 90 0 1 0 190 100
A2 8 0 1 0 182 100
A82 82 0 1 1 100 18
A4 4 0 0 0 100 10
Z
`
          }))
          .rotate({
            z: 1,
            angle: this.angle
          })
          .animation({
            duration: 1000,
            curve: Curve.Linear,
            iterations: -1,
            expectedFrameRateRange: {
              min: 20,
              max: 60,
              expected: 60,
            }
          })
          .scale({ x: 0.9, y: 0.9 })
      } else if (this.image) {
        Image(this.image)
          .fitOriginalSize(true)
          .objectFit(ImageFit.None)
      }
      if (this.msg) {
        Text(this.msg)
          .fontColor(Color.White)
          .textAlign(TextAlign.Center)
          .padding({ top: this.type == WTRHUDType.Loading || this.image ? 10 : 0 })
      }
    }
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .padding(12)
    .margin(30)
    .backgroundColor(Color.Black)
    .borderRadius(10)
    .shadow({ radius: 10, color: Color.Gray, offsetX: 3, offsetY: 0 })
  }
}

let _dialogController: CustomDialogController | null
let _cancelCallBack: (() => void) | undefined
let tmpHUDArray: WTRHUD[] = new Array()

@Component
export struct WTRHUD {
  showLoading(
    msg: string | WTRHUDParam = "",
    cancelCallBack?: () => void,
    alignment?: DialogAlignment,
    offset?: Offset,
    showInSubWindow?: boolean,
    isModal?: boolean,
    tmpHUDNum: number = 1, //缓存HUD的数量,用于多层返回HUD不显示情况
  ): void {
    if (typeof msg == 'string') {
      this.showType(WTRHUDType.Loading, undefined, msg, cancelCallBack, alignment, offset, showInSubWindow, isModal)
    } else {
      this.showType(WTRHUDType.Loading, undefined, msg.msg, msg.cancelCallBack, msg.alignment, msg.offset, msg.showInSubWindow, msg.isModal)
      tmpHUDNum = msg.tmpHUDNum ?? 1
    }

    //用于解决网络返回或者其它情况下不显示的问题
    if (tmpHUDArray.length < tmpHUDNum) {
      for (let index = 0; index < tmpHUDNum; index++) {
        tmpHUDArray.push(new WTRHUD());
      }
    }
  }

  showInfo(
    msg: string | WTRHUDParam = "",
    cancelCallBack?: () => void,
    alignment?: DialogAlignment,
    offset?: Offset,
    showInSubWindow?: boolean,
    isModal?: boolean,
  ): void {
    if (typeof msg == 'string') {
      this.showType(WTRHUDType.Info, undefined, msg, cancelCallBack, alignment, offset, showInSubWindow, isModal)
    } else {
      this.showType(WTRHUDType.Info, undefined, msg.msg, msg.cancelCallBack, msg.alignment, msg.offset, msg.showInSubWindow, msg.isModal)
    }
  }

  showSuccess(
    msg: string | WTRHUDParam = "",
    cancelCallBack?: () => void,
    alignment?: DialogAlignment,
    offset?: Offset,
    showInSubWindow?: boolean,
    isModal?: boolean,
  ): void {
    if (typeof msg == 'string') {
      this.showType(WTRHUDType.Success, $r("app.media.wtr_success"), msg, cancelCallBack, alignment, offset, showInSubWindow, isModal)
    } else {
      this.showType(WTRHUDType.Success, $r("app.media.wtr_success"), msg.msg, msg.cancelCallBack, msg.alignment, msg.offset, msg.showInSubWindow, msg.isModal)
    }
  }

  showError(
    msg: string | WTRHUDParam = "",
    cancelCallBack?: () => void,
    alignment?: DialogAlignment,
    offset?: Offset,
    showInSubWindow?: boolean,
    isModal?: boolean,
  ): void {
    if (typeof msg == 'string') {
      this.showType(WTRHUDType.Error, $r("app.media.wtr_error"), msg, cancelCallBack, alignment, offset, showInSubWindow, isModal)
    } else {
      this.showType(WTRHUDType.Error, $r("app.media.wtr_error"), msg.msg, msg.cancelCallBack, msg.alignment, msg.offset, msg.showInSubWindow, msg.isModal)
    }
  }

  showType(
    type: WTRHUDType,
    image: Resource | undefined,
    msg: string,
    cancelCallBack?: () => void,
    alignment: DialogAlignment = DialogAlignment.Center,
    offset: Offset = { dx: 0, dy: 0 },
    showInSubWindow: boolean = false,
    isModal: boolean = false,
    useTmpHUD: boolean = true //是否使用缓存的HUD
  ): void {
    let self: WTRHUD | undefined = this
    if (useTmpHUD && tmpHUDArray.length > 0) {
      self = tmpHUDArray.shift()
    }
    self?.showTypeReal(type, image, msg, cancelCallBack, alignment, offset, showInSubWindow, isModal)
  }

  private showTypeReal(
    type: WTRHUDType,
    image: Resource | undefined,
    msg: string,
    cancelCallBack?: () => void,
    alignment: DialogAlignment = DialogAlignment.Center,
    offset: Offset = { dx: 0, dy: 0 },
    showInSubWindow: boolean = false,
    isModal: boolean = false,
  ): void {
    this.hide()

    _cancelCallBack = cancelCallBack
    let animate: AnimateParam = {
      duration: 90,
      delay: 0,
      curve: Curve.EaseInOut
    }

    _dialogController = new CustomDialogController({
      builder: _WTRHUD({ type: type, image: image, msg: msg }),
      autoCancel: false,
      cancel: () => {
        _dialogController = null
        if (_cancelCallBack) {
          _cancelCallBack()
        }
      },
      customStyle: true,
      alignment: alignment,
      offset: offset,
      maskColor: 0x01000000,
      openAnimation: animate,
      closeAnimation: animate,
      showInSubWindow: showInSubWindow,
      isModal: isModal, //api 11 是否有蒙层
    })
    _dialogController.open()
    if (type != WTRHUDType.Loading) {
      let time: number = WTRHUDTime.baseTime;
      if (msg) {
        time += msg.length * WTRHUDTime.wordTime
      }
      time = Math.max(time, WTRHUDTime.minTime)
      time = Math.min(time, WTRHUDTime.maxTime)
      setTimeout(() => {
        this.hide()
      }, time)
    }
  }

  hide() {
    if (_dialogController) {
      _dialogController.close()
      _dialogController = null
      if (_cancelCallBack) {
        _cancelCallBack()
      }
    }
  }

  build() {
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进