Harmony OS:全模态对话框(广告)与文本切换功能实现

一、适用版本

本文所述功能适用于 Harmony OS NEXT / 5.0 / API 12 + 版本,确保在这些版本的鸿蒙系统上能顺利实现并展现预期效果。

二、效果展示

三、实现逻辑

(一)组件状态管理

通过 @State 装饰器定义多个状态变量,如 messageshowMessageshowDialogtimertimerCount,分别用于存储文本内容、控制文本显示状态、控制对话框显示状态、存储定时器标识以及倒计时数值,以此来管理组件内不同元素的状态变化。

(二)对话框内容构建

利用 @Builder 装饰器创建 getDialogContent 方法,在该方法内使用 ColumnRow 布局容器搭建对话框的结构,包含倒计时文本显示和关闭按钮,为用户提供清晰的交互界面。

(三)倒计时逻辑实现

beginCount 方法中借助 setInterval 函数实现倒计时功能,每秒更新一次 timerCount 的值。当 timerCount 减为 0 时,清除定时器,重置 timerCount 的值并关闭对话框,实现倒计时与对话框关闭的联动逻辑。

(四)组件生命周期处理

通过 aboutToAppearaboutToDisappear 这两个组件生命周期方法,在组件即将显示时自动打开对话框并启动倒计时,在组件即将消失时清除定时器,确保资源的合理利用和功能的正常运行。

(五)页面布局与交互

build 方法中,使用 Column 布局将页面分为内容区域和按钮区域。内容区域根据 showMessage 的状态显示不同文本,按钮区域的两个按钮分别绑定相应的点击事件,实现文本动画切换和打开全模态对话框的功能。最后通过 bindContentCover 将对话框以全模态形式展示在页面上,并设置默认的模态过渡效果。

四、源码

(一)组件源码

css 复制代码
@Entry
@Component
struct BindContentCover {
    @State message: string = 'Hello World';
    @State showMessage: boolean = false;
    @State showDialog: boolean = false;
    @State timer: number = -1;
    @State timerCount: number = 3;

    @Builder
    getDialogContent() {
        return Column() {
            Row() {
                Text(`${this.timerCount}`)
                   .height(28)
                   .fontSize(28)
                   .fontWeight(FontWeight.Bold)
                   .fontColor(Color.White)
                   .margin(25);
            }
           .width('100%')
           .justifyContent(FlexAlign.End)
           .padding(20);

            Button('关闭对话框')
               .width(160)
               .height(50)
               .backgroundColor(Color.White)
               .fontColor(Color.Black)
               .fontSize(18)
               .fontWeight(FontWeight.Medium)
               .borderRadius(25)
               .onClick(() => {
                    this.showDialog = false;
                });
        }
       .width('100%')
       .height('100%')
       .backgroundColor(Color.Orange);
    }

    beginCount() {
        this.timer = setInterval(() => {
            if (this.timerCount === 0) {
                clearInterval(this.timer);
                this.timerCount = 5;
                this.showDialog = false;
                return;
            }
            this.timerCount--;
        }, 1000);
    }

    aboutToDisappear(): void {
        clearInterval(this.timer);
    }

    aboutToAppear(): void {
        this.showDialog = true;
        this.beginCount();
    }

    build() {
        return Column() {
            // 内容区域
            Column() {
                if (this.showMessage) {
                    Text(this.message)
                       .fontSize(50)
                       .fontWeight(FontWeight.Bolder)
                       .fontColor(Color.Blue);
                } else {
                    Text('点击按钮显示文本')
                       .fontSize(18)
                       .fontColor(Color.Gray);
                }
            }
           .height(120)
           .width('100%')
           .justifyContent(FlexAlign.Center)
           .alignItems(HorizontalAlign.Center)
           .border({ width: 2, color: Color.Gray, style: BorderStyle.Dashed })
           .borderRadius(8)
           .margin({ bottom: 40 });

            // 按钮区域
            Column() {
                Button('文本动画切换')
                   .width('90%')
                   .height(55)
                   .backgroundColor(Color.Blue)
                   .fontColor(Color.White)
                   .fontSize(18)
                   .fontWeight(FontWeight.Medium)
                   .borderRadius(10)
                   .margin({ bottom: 20 })
                   .onClick(() => {
                        animateTo({ duration: 1000 }, () => {
                            this.showMessage =!this.showMessage;
                        });
                    });

                Button('打开全模态对话框')
                   .width('90%')
                   .height(55)
                   .backgroundColor(Color.Orange)
                   .fontColor(Color.White)
                   .fontSize(18)
                   .fontWeight(FontWeight.Medium)
                   .borderRadius(10)
                   .onClick(() => {
                        this.showDialog = true;
                        this.beginCount();
                    });
            }
           .width('100%')
           .alignItems(HorizontalAlign.Center);
        }
       .width('100%')
       .height('100%')
       .justifyContent(FlexAlign.Center)
       .padding(30)
       .backgroundColor(Color.Orange)
       .bindContentCover(this.showDialog, this.getDialogContent(), {
            modalTransition: ModalTransition.DEFAULT
        });
    }
}

(二)Ability 源码

javascript 复制代码
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

const DOMAIN = 0x0000;

export default class EntryAbility extends UIAbility {
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        try {
            this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
        } catch (err) {
            hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
        }
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
    }

    onDestroy(): void {
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
    }

    onWindowStageCreate(windowStage: window.WindowStage): void {
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

        windowStage.getMainWindow().then((mainWindow) => {
            mainWindow.setWindowLayoutFullScreen(true).then(() => {
                hilog.info(DOMAIN, 'testTag', 'Succeeded in setting full screen layout.');
            }).catch((fullScreenErr: BusinessError) => {
                hilog.error(DOMAIN, 'testTag', 'Failed to set full screen layout. Cause: %{public}s', JSON.stringify(fullScreenErr));
            });
        }).catch((err: BusinessError) => {
            hilog.error(DOMAIN, 'testTag', 'Failed to get main window. Cause: %{public}s', JSON.stringify(err));
        });

        windowStage.loadContent('pages/bindContentCover', (err) => {
            if (err.code) {
                hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
                return;
            }
            hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
        });
    }

    onWindowStageDestroy(): void {
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
    }

    onForeground(): void {
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
    }

    onBackground(): void {
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
    }
}

五、源码详细分析

(一)EntryAbility 部分

  1. onCreate 方法
    • 尝试通过 this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET) 设置应用的颜色模式,以确保应用在不同设备和主题下有一致的显示效果。
    • 使用 try - catch 块捕获可能出现的错误,并通过 hilog 工具记录错误信息,便于开发者定位问题。
  2. onWindowStageCreate 方法
    • 首先获取主窗口 windowStage.getMainWindow(),然后将窗口设置为全屏模式 mainWindow.setWindowLayoutFullScreen(true)。通过 then - catch 处理设置成功与失败的情况,成功时记录成功日志,失败时记录错误日志。
    • 接着使用 windowStage.loadContent('pages/bindContentCover') 加载包含 BindContentCover 组件的页面,同样通过 then - catch 处理加载过程中的成功与失败情况,并记录相应日志。
  3. 其他生命周期方法onDestroyonWindowStageDestroyonForegroundonBackground 方法通过 hilog 记录日志,用于跟踪应用在不同生命周期阶段的状态变化,帮助开发者理解应用的运行流程。

(二)BindContentCover 组件部分

  1. 状态变量
    • @State message 存储要显示的核心文本内容,初始值为 'Hello World',可以根据业务需求进行修改。
    • @State showMessage 作为一个布尔型状态变量,控制 message 文本的显示与隐藏,从而实现文本切换效果。
    • @State showDialog 同样是布尔型变量,用于控制全模态对话框的显示与隐藏。
    • @State timer 用于存储 setInterval 创建的定时器标识,以便在需要时清除定时器,避免内存泄漏。
    • @State timerCount 存储倒计时的数值,控制对话框中倒计时的显示与逻辑。
  2. 对话框构建方法 getDialogContent
    • 使用 ColumnRow 布局容器搭建对话框结构。Row 中放置倒计时文本,通过设置 heightfontSizefontWeightfontColormargin 等属性,使其在右上角以合适的样式显示。
    • Button 组件作为关闭对话框的操作按钮,设置了 widthheightbackgroundColorfontColorfontSizefontWeightborderRadius 等样式属性,并绑定点击事件,点击时将 showDialog 设置为 false,从而关闭对话框。
  3. 倒计时方法 beginCount
    • 使用 setInterval 函数创建一个定时器,每 1000 毫秒(1 秒)执行一次回调函数。
    • 在回调函数中,检查 timerCount 是否为 0。如果为 0,清除定时器 clearInterval(this.timer),重置 timerCount 为 5,并将 showDialog 设置为 false,关闭对话框。否则,将 timerCount 的值减 1。
  4. 组件生命周期方法
    • aboutToAppear 方法在组件即将显示时调用,将 showDialog 设置为 true,打开对话框,并调用 beginCount 方法启动倒计时,确保每次组件显示时对话框和倒计时都能正常工作。
    • aboutToDisappear 方法在组件即将消失时调用,清除定时器 clearInterval(this.timer),防止定时器持续运行造成内存泄漏。
  5. 页面构建方法 build
    • 使用 Column 布局将页面分为上下两部分。上半部分为内容区域,根据 showMessage 的值决定显示 message 文本还是提示点击的文本,并对文本进行样式设置,包括 fontSizefontWeightfontColorborderborderRadius 等,同时设置了高度、宽度、对齐方式和下边距。
    • 下半部分为按钮区域,同样使用 Column 布局。两个 Button 组件分别设置了 widthheightbackgroundColorfontColorfontSizefontWeightborderRadius 等样式属性,并绑定相应的点击事件。"文本动画切换" 按钮通过 animateTo 方法实现文本显示状态的平滑切换,"打开全模态对话框" 按钮则打开对话框并启动倒计时。
    • 最后,通过 bindContentCover 方法将对话框以全模态形式展示在页面上,并设置 modalTransitionModalTransition.DEFAULT,即默认的模态过渡效果。

六、错误处理

在开发过程中,可能会遇到以下常见错误:

(一)页面加载失败

  1. 产生原因pages/bindContentCover 路径配置错误,或者该页面文件不存在。
  2. 解决方法:仔细检查路径是否与项目目录结构一致,确保页面文件存在且位置正确。可以通过打印日志或在开发工具中查看文件路径来辅助排查问题。

(二)定时器未清除导致内存泄漏

  1. 产生原因 :在组件销毁时(如 aboutToDisappear 方法中)未正确清除定时器,使得定时器持续运行。
  2. 解决方法 :确保在 aboutToDisappear 方法中调用 clearInterval(this.timer),以清除定时器,释放资源。同时,可以在控制台打印日志,确认定时器是否被正确清除。

(三)样式显示异常

  1. 产生原因:样式属性设置错误,例如颜色值、尺寸单位等设置不符合要求,或者布局容器嵌套错误。
  2. 解决方法:仔细检查样式属性的设置,参考官方文档确认颜色值、尺寸单位等的正确使用方法。对于布局容器嵌套问题,可以通过打印布局结构或在开发工具的预览功能中查看布局情况,逐步排查并调整布局。

七、总结

本功能如同为鸿蒙应用打造了一套有趣且实用的交互 "工具箱",主要实现了三个关键功能:一是通过按钮点击实现文本的平滑切换,为用户提供不同的提示信息;二是能够打开全模态对话框,并带有倒计时功能,增加了交互的趣味性和实用性;三是通过合理的组件生命周期管理和状态控制,确保功能的稳定运行。核心在于以简洁明了的代码逻辑,实现丰富多样的用户交互效果,为用户带来流畅、有趣的使用体验。同时,通过对可能出现的错误进行分析和处理,帮助开发者在开发过程中避免常见问题,提高开发效率和应用质量。

相关推荐
搞瓶可乐3 小时前
【HarmonyOS开发】鸿蒙应用开发发展史:从技术探索到生态爆发,一文读懂其演进脉络
harmonyos·arkts
互联网散修3 小时前
鸿蒙(HarmonyOS)ArkTS 实战: animateTo属性动画实现连续涟漪扩散
华为·harmonyos·鸿蒙属性动画
lxysbly7 小时前
鸿蒙harmonyos端怀旧游戏模拟器,支持fc红白机 街机 gba psp ps1 nds n64世嘉md gbc gb sfc等主机
游戏·华为·harmonyos
ShuiShenHuoLe8 小时前
02Navigation页面路由
harmonyos·鸿蒙
飞凌嵌入式8 小时前
飞凌嵌入式RK3506J核心板通过OpenHarmony 5.1兼容性认证
嵌入式硬件·开源·鸿蒙
想你依然心痛8 小时前
HarmonyOS 5.0行业解决方案:基于端侧AI的智能工业质检APP开发实战
人工智能·华为·harmonyos
Sylus_sui9 小时前
鸿蒙 HarmonyOS 4.0+ 音乐播放器企业级完整实现(后台播放 + 系统播控中心 + 全功能)
华为·harmonyos
轻口味10 小时前
HarmonyOS 6 原生高性能相机框架:GPUImage (libgpuimagelib) 深度架构解析与实战全纪录
数码相机·架构·harmonyos
小雨青年11 小时前
鸿蒙 HarmonyOS 6 | 网络请求超时重试与弱网适配深度解析
网络·华为·harmonyos