|

UI

HarmonyOS NEXT

全局Loading弹窗:用子窗口的形式来实现(HarmonyOS NEXT共享包依赖版)

【过时提醒】本篇文档所述创建loading弹窗的方式使用起来较为复杂,请参考下面方式:https://developer.huawei.com/consumer/cn/forum/topic/0203147021096254151?fid=0109140870620153026
因为自定义弹窗在按下返回键或ESC键后会消失,有时候并不能满足实际需求,所以考虑采用创建子窗口的方式来实现,子窗口天生对返回事件免疫。小生能力有限,欢迎各位方家指正。

【注】预览器下并无效果,请使用真机或模拟器测试~

1.创建共享包(如loadingLib,本示例在项目根目录下创建)

2.在loadingLib共享包中创建加载要显示的Page页面(LoadingPage.ets)

  • 为LoadingPage指定路由名称,即:@Entry({ routeName: 'LoadingPage' })
深色代码主题
复制
@Entry({ routeName: 'LoadingPage' })
@Component
struct LoadingPage {
  @StorageProp('loading_message') message: string = '请稍候'

  build() {
    Stack({ alignContent: Alignment.Center }) {
      Column() {
        LoadingProgress().width(30).height(30).color(Color.White)

        Text(this.message ?? '请稍候')
          .fontColor(Color.White)
          .fontSize(16)
          .margin({ top: 15 })
          .width('100%')
          .textAlign(TextAlign.Center)
      }
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .backgroundColor('#88000000')
      .borderRadius(8)
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Transparent)
  }
}

3.创建LoadingUtils类用于创建子窗口(LoadingUtils.ts),需要导出

  • 导入LoadingPage.ets页面:import 'loadingLib/src/main/ets/pages/LoadingPage.ets'
  • 子窗口使用路由名称加载页面:await win.loadContentByName('LoadingPage')
  • 在loadingLib共享包默认生成的Index.ets中导出LoadingUtils类:
深色代码主题
复制
export { LoadingUtils } from "./src/main/ets/utils/LoadingUtils"
  • LoadingUtils代码如下:
深色代码主题
复制
import window from '@ohos.window';
import display from '@ohos.display';
import common from '@ohos.app.ability.common';
import UIAbility from '@ohos.app.ability.UIAbility';
import 'loadingLib/src/main/ets/pages/LoadingPage.ets'

/**
 * 通过创建子窗口来显示Loading弹窗
 */
export class LoadingUtils {
  private static EVENT_CREATE_SUB_WINDOW = 'createSubWindow'
  private static EVENT_CLOSE_SUB_WINDOW = 'closeSubWindow'
  static LOADING_MESSAGE = 'loading_message'

  /**
   * 发送创建loading子窗口的事件,显示loading
   * @param context context
   */
  static showLoading(context: common.UIAbilityContext, message: string = '请稍候') {
    AppStorage.setOrCreate(LoadingUtils.LOADING_MESSAGE, message)
    context?.eventHub.emit(LoadingUtils.EVENT_CREATE_SUB_WINDOW)
  }

  /**
   * 发送关闭loading子窗口的事件,隐藏loading
   * @param context context
   */
  static hideLoading(context: common.UIAbilityContext) {
    context?.eventHub.emit(LoadingUtils.EVENT_CLOSE_SUB_WINDOW)
  }

  /**
   * 订阅创建和关闭loading子窗口的事件
   * @param ability ability
   * @param stage stage
   */
  static subscribeLoadingEvent(ability: UIAbility, stage: window.WindowStage) {
    if (ability) {
      ability.context.eventHub.on(LoadingUtils.EVENT_CREATE_SUB_WINDOW, () => LoadingUtils.showSubWindow(stage))
      ability.context.eventHub.on(LoadingUtils.EVENT_CLOSE_SUB_WINDOW, () => LoadingUtils.closeSubWindow(stage))
    }
  }

  /**
   * 取消订阅创建和关闭loading子窗口的事件
   * @param ability ability
   */
  static unsubscribeLoadingEvent(ability: UIAbility) {
    if (ability) {
      ability.context.eventHub.off(LoadingUtils.EVENT_CREATE_SUB_WINDOW)
      ability.context.eventHub.off(LoadingUtils.EVENT_CLOSE_SUB_WINDOW)
    }
  }

  /**
   * 显示loading子窗口
   * @param stage stage
   */
  static async showSubWindow(stage: window.WindowStage) {
    stage?.createSubWindow('sub_window').then(async win => {
      // 设置子窗口显示的页面
      await win.loadContentByName('LoadingPage')
      // 设置全屏
      let d = display.getDefaultDisplaySync()
      let windowClass = stage.getMainWindowSync()
      await win.setWindowSystemBarEnable([])
      await win.setWindowLayoutFullScreen(true)
      await win.resize(d.width, d.height)
      // 设置半透明效果
      win.setWindowBackgroundColor('#88000000')
      win.showWindow()
    })
  }

  /**
   * 关闭loading子窗口
   * @param stage stage
   */
  static closeSubWindow(stage: window.WindowStage) {
    stage?.getSubWindow().then(win => {
      if (win.length > 0) {
        win[0].destroyWindow()
      }
    })
  }
}

4.在需要使用loadingLib共享包的module(如entry)中配置oh-package.json5依赖:

深色代码主题
复制
{
  "name": "entry",
  ...
  "dependencies": {
    ...
    "loadingLib": "file:../loadingLib"
  }
}

5.根据UIAbility生命周期回调,实现子窗口事件订阅与取消

  • 方案1:创建MyAbilityStage.ets并配置:
深色代码主题
复制
export default class MyAbilityStage extends AbilityStage {
  
  onCreate() {
    this.context.getApplicationContext().on('abilityLifecycle', this.abilityLifecycleCallback)
  }
  
  /**
   *  声明ability生命周期回调,需配置所有回调后才可以在applicationContext注册
   */
  abilityLifecycleCallback: AbilityLifecycleCallback = {
    onAbilityCreate(ability: UIAbility) {},

    onWindowStageCreate(ability: UIAbility, windowStage: window.WindowStage) {
      // 订阅子窗口事件
      LoadingUtils.subscribeLoadingEvent(ability, windowStage)
    },

    onWindowStageActive(ability: UIAbility, windowStage: window.WindowStage) {},

    onWindowStageInactive(ability: UIAbility, windowStage: window.WindowStage) {},

    onWindowStageDestroy(ability: UIAbility, windowStage: window.WindowStage) {
      LoadingUtils.unsubscribeLoadingEvent(ability)
    },

    onAbilityDestroy(ability: UIAbility) {},

    onAbilityForeground(ability: UIAbility) {},

    onAbilityBackground(ability: UIAbility) {},

    onAbilityContinue(ability: UIAbility) {}
  }
}
深色代码主题
复制
"module": {
    ...
    "srcEntry": './ets/MyAbilityStage.ets',
    ...
}
  • 方案2:直接在UIAbility中引用LoadingUtils类:
深色代码主题
复制
export default class YourAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    ...
    LoadingUtils.subscribeLoadingEvent(this, windowStage)
  }

  onWindowStageDestroy(): void {
    LoadingUtils.unsubscribeLoadingEvent(this)
  }
}

6.在Page或组件中使用:

  • 显示loading:
深色代码主题
复制
LoadingUtils.showLoading(getContext(this) as common.UIAbilityContext, '加载中')
  • 隐藏loading:
深色代码主题
复制
LoadingUtils.hideLoading(getContext(this) as common.UIAbilityContext)
点赞
7
收藏
9
回复
43
分享
举报
浏览3737 编辑于2024-06-05 01:56天津
全部评论
最多点赞
最新发布
最早发布
写回答
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。
发表

我要发帖子

了解社区公约,与您携手共创和谐专业的开发者社区。