写点什么

【HarmonyOS】关于鸿蒙原生实现红包雨效果的方案设计

  • 2025-03-21
    安徽
  • 本文字数:3726 字

    阅读完需:约 12 分钟

开发语言:ArkTs开发工具:DevEco Studio 5.0.0 ReleaseAPI 版本:API 12


demo 演示Gitee:harmony-red-packet-rain.git



最近项目在做鸿蒙化,按照原需求需要实现红包雨的活动效果,下面介绍一下实现红包雨效果的思路:


需求:全屏展示,每隔 1s 下落 3 个红包,每个红包的下落时长随机生成,随机点击 1~5 次后中奖。

一、全屏展示实现:

使用window.createWindow()实现全屏半透明的弹窗,将红包雨页面 page 作为 window 的内容视图。


showWindowDialog(callback?: ()=>void): void {  let date = new Date()  this.dialogConfig = {    name: this.name + date.getMinutes().toString(),    windowType: window.WindowType.TYPE_DIALOG,    ctx: getContext()  }  window.createWindow(this.dialogConfig, (string, newWindow: window.Window) => {    if (!newWindow) {      return;    }    this.dialogWindow = newWindow;    newWindow.setWindowTouchable(true);    newWindow.setUIContent('pages/HMRedPacketRainPage').then(()=>{      newWindow.setWindowBackgroundColor(this.winBgColor);    })    newWindow.showWindow(()=>{      if (callback !== undefined) {        callback();      }    })  })}
复制代码

二、红包雨实现

方案一:

红包开始下落前一次性创建所有红包,并添加到数据源数组中,所有红包每 3 个一组,分别给每组红包设置延迟下落的时间,第一组延迟 0s,第二组延迟 1s,第三组延迟 2s,以此类推,从而实现红包雨的效果。

1、创建红包数据模型

每个红包对象属性:宽、高、位置x坐标、位置y坐标、开始位置、结束位置、下落时长、红包间距、延迟下落时间。


import display from "@ohos.display"
@Observedexport class HMRedPacketModel { width: number = 76.5; height: number = 84; x: number = 0; y: number = -85; start: number = -85; end: number = this.getDeviceHeight(); duration: number = 2000 + (HMRedPacketModel.getRandomNumber(0, 255) % 250 / 100) * 1000; space: number = (this.getDeviceWidth()-84*3-20)/4.0; delay: number = 0;
constructor(index: number, time?: number) { this.x = 10 + this.height * (index-1) + this.space * index; if (delay) { this.delay = delay * 1000; } }
/** * 获取随机数 * @param min 最小值 * @param max 最大值 * @returns */ static getRandomNumber(min: number, max: number) { let num = Math.floor(Math.random() * (max - min + 1)) + min; return num; }
/** * 获取屏幕宽度 * @returns */ getDeviceWidth(): number { return px2vp(display.getDefaultDisplaySync().width); }
/** * 获取屏幕高度 * @returns */ getDeviceHeight(): number { return px2vp(display.getDefaultDisplaySync().height); }}
复制代码
2、创建红包雨组件,添加下落动画

使用帧动画AnimatorResult实现红包的下落效果,可以实现监听动画过程onFrame()、动画结束onFinish()、动画取消onCancel()等事件,并且提供开始动画play()、暂停动画pause()等方法。


// 红包对象@ObjectLink model: HMRedPacketModel;// 下落动画是否完成@State downFinish: boolean = false;// 帧动画animatorResult: AnimatorResult | undefined = undefined;
aboutToAppear(): void { // 帧动画 let animatorOption: AnimatorOptions = { duration: this.model.duration, delay: this.model.delay, easing: 'linear', iterations: 1, fill: 'forwards', direction: 'normal', begin: this.model.start, end: this.model.end } this.animatorResult = this.getUIContext().createAnimator(animatorOption); this.animatorResult.onFrame = (progress: number) => { this.model.y = progress; // 动画执行结束释放 if (progress == this.model.end) { console.info('HMRedPacketWidget', '执行到结束为止'+progress.toString()) this.downFinish = true; this.animatorResult?.pause(); clearTimeout(this.startTimeout); } }; this.animatorResult.onCancel = () => { console.info("HMRedPacketWidget", '动画取消'); }; this.animatorResult.onFinish = () => { console.info("HMRedPacketWidget", '动画完成'); this.downFinish = true; }; this.animatorResult.onRepeat = () => { console.info("HMRedPacketWidget", '动画重复播放'); }; // 开始动画 this.animatorResult?.play();}
复制代码
3、创建红包雨数据源
@State redPacketModels: HMRedPacketModel[] = [];
/** * 创建红包雨对象数组 */createAllRedRainModels() { for (let index = 0; index < 15; index++) { this.redPacketModels.push(new HMRedPacketModel(1, index)); this.redPacketModels.push(new HMRedPacketModel(2, index)); this.redPacketModels.push(new HMRedPacketModel(3, index)); }}
复制代码
4、展示红包雨
@Entry@Componentstruct HMRedPacketRainPage {  // 红包雨下落总时长  static RED_PACKET_DOWN_TOTAL_TIME: number = 15;    @State marginTop: number = 0;  @State redPacketModels: HMRedPacketModel[] = [];  @State showResult: boolean = false;  private interval: number = 0;  private timer: number = 0;  private clickRedPacketCount: number = 0;  private showResultCount: number = HMRedPacketModel.getRandomNumber(1, 5);  /**   * 创建红包雨对象数组   */  createAllRedRainModels() {    for (let index = 0; index < HMRedPacketRainPage.RED_PACKET_DOWN_TOTAL_TIME; index++) {      this.redPacketModels.push(new HMRedPacketModel(1, index));      this.redPacketModels.push(new HMRedPacketModel(2, index));      this.redPacketModels.push(new HMRedPacketModel(3, index));    }  }
/** * 页面展示 */ onPageShow(): void { // 一次性创建所有红包雨对象 this.createAllRedRainModels(); // 定时器 this.timer = setTimeout(() => { this.closePage(); }, HMRedPacketRainPage.RED_PACKET_DOWN_TOTAL_TIME * 1000); }
onPageHide(): void { this.closePage(); } /** * 关闭当前页面 */ closePage() { HMWindowDialog.getInstance().closeWindowDialog(); clearInterval(this.interval); clearTimeout(this.timer) }
build() { Stack() { // 红包雨 ForEach(this.redPacketModels, (model: HMRedPacketModel) => { // 红包雨 HMRedPacketWidget({model: model, onClickRedPacket: () => { this.clickRedPacketCount++; if (this.clickRedPacketCount === this.showResultCount) { this.showResult = true; clearInterval(this.interval) clearTimeout(this.timer); } }}) }) if (this.showResult) { HMRedPacketResultWidget(); }
// 关闭按钮 Row() { Image($rawfile('redPacketRain/redRain_close.png')) .width(36) .height(36) .margin({right: 15}) .onClick(() => { this.closePage(); }) } .width('100%') .height(40) .margin({top: 50}) .justifyContent(FlexAlign.End) .alignItems(VerticalAlign.Center) } .height('100%') .width('100%') .clip(true) .alignContent(Alignment.TopStart) .backgroundColor(Color.Transparent) }
}
复制代码

方案二

定义红包数据源数组,每隔 1s 创建 3 个红包,添加到红包数据源中,通过数据改变驱动 UI 刷新,由于鸿蒙的 UI 刷新逻辑是状态改变驱动 UI 刷新,当第 2 组红包下落的时,由于数据源发生改变,会驱动整体 UI 刷新,导致前面的红包回到初始状态再次下落,该问题无法解决。<br>该问题也给华为提过工单,收到的回复是暂无更好的实现方式:


问题:

问题一:在方案一中,一次性创建那么多红包,会不会影响性能?<br>由于单个红包图片很小,占用内存也不会太大,在开发中验证了一次性创建上百的红包,暂时未出现性能问题;并且由于方案二无法实现,所以暂时没有发现更好的实现方案。相信我们的“遥遥领先”,性能绝对没问题。<br>


问题二:在方案一中,红包下落过程中,偶尔会有卡顿的情况?<br>该问题使用开发工具的Profiler调试,发现红包在下落过程中,FPS60-120之间跳动,通过修改手机设置-显示和亮度-屏幕刷新率设置为固定60Hz120Hz时,可解决此问题。下面是工单官方的回复:


结尾

如大家有更好的实现方案,还请评论回复,一起探讨学习,感谢!

发布于: 刚刚阅读数: 3
用户头像

还未添加个人签名 2025-03-18 加入

还未添加个人简介

评论

发布
暂无评论
【HarmonyOS】关于鸿蒙原生实现红包雨效果的方案设计_鸿蒙_走向菜鸟的菜鸟_InfoQ写作社区