HarmonyOS7跑马灯综合示例实战:Marquee 常用参数与组合场景串联

文章目录

      • 前言
      • 别急着抄,先认结构
      • 这页有没有灵魂,主要看状态怎么带
      • 时间不多的话,先盯这几个入口
      • 第一段关键代码:页面是怎么被带起来的
      • 第二段关键代码:真正决定交互手感的地方
      • 如果你要亲手试,顺序最好别乱
      • 真放到业务里,我会先改什么
      • 它的参考价值不只是把效果跑出来
      • 完整代码
      • 收个尾

前言

如果你只看单个跑马灯属性,容易觉得它没什么难度。但把不同方向、速度、循环和容器样式放到一页里之后,Marquee 的使用边界就会一下子清楚很多。这个综合示例很适合做组件学习收口。 这一页适合慢一点读,不是因为代码特别难,而是因为它里面很多决定都和真实页面很像。把这些决定看懂,比把组件名字记住更值钱。

如果把这页当成练习材料,我会优先看它怎样围绕 Marquee 常用参数与组合场景串联 组织页面。因为这一层想清楚了,后面的代码基本就不会散。

这类写法尤其适合落在 组件教学页、公告能力演示页、滚动信息模板页 这些场景里,所以我下面不会只讲“组件怎么写”,而是更关心“放进页面之后为什么这样组织”。

别急着抄,先认结构

这一类页面看源码最怕的就是“每一段都认识,但拼起来不知道为什么这么摆”。所以这里先从页面骨架讲起,比直接盯属性更省时间。

页面区域主要职责在代码里的典型表现
头部说明区交代当前案例在演示什么Text标题、补充说明、标签文案
核心展示区承载组件能力的主要效果ColumnRow、业务组件本体
辅助信息区补充状态、标签、分组或统计信息次级文本、角标、分组标题、描述块
交互入口区负责切换、返回、定位、选择等动作点击事件、按钮、索引条、导航入口

这一页没有额外拆出接口,页面更多是直接围绕基础数据和组件参数展开。

这个案例表面看是界面效果,真正该盯的是状态怎么流动,因为大多数可复用价值都藏在这里。

这页有没有灵魂,主要看状态怎么带

综合示例最怕写成“效果很多,但彼此没关系”。这页之所以还算值得看,不是因为它摆了几种样式,而是因为它用一个isRunning把整页的跑马灯都串了起来,让你能一眼看到统一控制的价值。

  • isShow仍然只是演示容器的开关,不是阅读重点。
  • isRunning才是这篇真正的控制轴。它决定顶部按钮文案、状态小圆点颜色,以及下面所有Marqueestart参数是否继续生效。

这一点在业务里很常见。比如公告轮播页要支持“用户手动暂停”、运营位演示页要支持“一键停止所有动画”、低功耗场景可能要统一降级动效,这时候你就会发现:

  • 把动画开关集中成一个状态,比每个组件各管各的好维护得多。
  • 当一页里有多个跑马灯时,统一控制比局部控制更容易保持体验一致。
  • 状态一旦集中,后面无论接设置项、埋点还是生命周期暂停逻辑,都有明确落点。

所以别把isRunning看成一个简单布尔值。它其实是在示范“多个同类组件如何被一个页面状态统一调度”,这一层比单个Marquee参数更值得学。

时间不多的话,先盯这几个入口

我一般不会把所有方法从上到下读一遍,而是先找“用户动一下之后,页面为什么会变”的那条链路。

  • 这个案例没有太多额外方法,核心价值主要集中在页面结构和组件组合方式。

我自己读这类方法时,通常只抓一条线:谁触发、谁被改、页面哪里立刻有反馈。把这三件事连起来,很多交互代码一下就顺了。

第一段关键代码:页面是怎么被带起来的

这一段建议慢一点看。它通常决定了页面初始状态,也决定了后续哪些区域会跟着刷新。

@StateisShow:boolean=true@StateisRunning:boolean=truebuild(){Column(){if(this.isShow){Column({space:16}){Text('跑马灯综合示例').fontSize(20).fontWeight(FontWeight.Bold).fontColor(DEMO_THEME_COLOR)Text('综合展示 Marquee 所有特性和样式变化').fontSize(13).fontColor(DEMO_SUBTEXT_COLOR).width('100%')// 顶部控制栏Row({space:10}){Button(this.isRunning?'⏸ 全部暂停':'▶ 全部开始').fontSize(12).height(32).padding({left:14,right:14}).backgroundColor(this.isRunning?PRESET_COLORS[3].value:PRESET_COLORS[0].value)

这一段我通常不会一下翻过去,而是先确认下面这几个判断点:

  • @State字段到底在控制显示、选择、跳转结果还是模式切换。
  • 默认值是不是合理,页面一打开会不会就落在一个可理解的状态上。
  • 字段命名能不能让后来的人一眼看懂用途,而不是还要翻半天 UI。

第二段关键代码:真正决定交互手感的地方

这一段的价值,不只是按钮能点,而是它把“统一控制 + 即时反馈 + 批量生效”三个动作压在了一起。对组件演示页来说,这种组织方式非常重要,因为它能让读者立刻看懂状态变化带来的影响范围。

.onClick(()=>{this.isRunning=!this.isRunning})Row({space:6}){Circle({width:8,height:8}).fill(this.isRunning?'#4CAF50':'#F44336')Text(this.isRunning?'运行中':'已暂停').fontSize(12).fontColor(this.isRunning?'#4CAF50':'#F44336')}.layoutWeight(1).justifyContent(FlexAlign.End)}.width('100%')// 综合展示区域Column({space:10}){// 第一区:不同速度Text('速度梯度').fontSize(13).fontWeight(FontWeight.Medium).fontColor('#333333').width('100%')

你可以按下面这个顺序去理解它:

  1. 先有统一入口:顶部按钮不是某一个跑马灯的局部按钮,而是整页总开关。
  2. 再有可见反馈:圆点颜色和文字状态同步变化,用户不用盯着每一条跑马灯,也知道当前系统处于运行还是暂停。
  3. 最后批量影响子组件:下方所有Marqueestart都绑定到同一个isRunning,所以状态一变,整页动效一起变。

这类写法放进业务里也很常用。比如一个营销页里有多条滚动提示,你完全可以照这个思路接系统节能模式、页面失焦暂停、用户主动关闭动画等能力。换句话说,这段不是在炫技,而是在示范“同类动效如何被一个页面状态统一管理”。

如果你要亲手试,顺序最好别乱

如果你准备把这个案例交给团队里别的人看,我甚至建议直接让对方按下面的顺序自己操作一遍。很多理解偏差都会在这一步消失。

  1. 先进入页面,确认首屏是不是把跑马灯综合示例的主题交代清楚。
  2. 盯住核心展示区,观察默认状态下最醒目的内容是什么。
  3. 主动触发一次关键交互,比如点击、滑动、跳转、返回、切换或者选择。
  4. 回头检查状态区、提示区、标题区或者附属信息有没有跟着变化。
  5. 最后再打开源码,对照刚才那次交互,把状态变化链路串起来。

如果这五步你能边操作边说清楚页面发生了什么,后面再换成自己的数据和交互,心里会稳很多。

真放到业务里,我会先改什么

从教程页到业务页,差的从来不只是接口。更多时候,是组件职责、命名和状态来源要重新收拾一遍。

  • 公告条类页面别只盯滚动,字号、留白、边框和底色往往更影响可读性。
  • 如果后面要接运营文案,最好把内容源和样式配置拆开,避免每次改文案都动布局代码。
  • 只要页面里有重复块,就别硬撑着手写到底;早点抽成小组件,后面改样式和改交互都会轻松很多。
  • 示例数据最好和布局代码分开放,不然后面一接接口,页面文件很容易立刻变臃肿。

它的参考价值不只是把效果跑出来

很多官方示例的价值在于展示组件存在过,但这种页面更进一步:它在展示“组件被放进页面之后怎么活起来”。

  • 页面结构比较稳,后续不管是换数据还是换皮肤,成本都不会特别高。
  • 状态数量总体可控,适合拿来练“一个页面里如何分配职责”这件事。
  • 组件参数和页面目标之间关系比较直观,不太会出现“能跑但看不懂为什么这么配”的情况。

完整代码

下面保留整理过命名的完整 ArkTS 代码,方便你直接对照学习。这里已经去掉原始的 Demo 命名,改成了更贴近当前案例语义的名称。

/** * 跑马灯综合示例 */import{PRESET_COLORS,generateListItems,DEMO_BG_COLOR,DEMO_CARD_COLOR,DEMO_THEME_COLOR,DEMO_SUBTEXT_COLOR}from'./types'@Entry@Componentstruct MarqueeCompletePlaybook{@StateisShow:boolean=true@StateisRunning:boolean=truebuild(){Column(){if(this.isShow){Column({space:16}){Text('跑马灯综合示例').fontSize(20).fontWeight(FontWeight.Bold).fontColor(DEMO_THEME_COLOR)Text('综合展示 Marquee 所有特性和样式变化').fontSize(13).fontColor(DEMO_SUBTEXT_COLOR).width('100%')// 顶部控制栏Row({space:10}){Button(this.isRunning?'⏸ 全部暂停':'▶ 全部开始').fontSize(12).height(32).padding({left:14,right:14}).backgroundColor(this.isRunning?PRESET_COLORS[3].value:PRESET_COLORS[0].value).fontColor('#FFFFFF').borderRadius(16).onClick(()=>{this.isRunning=!this.isRunning})Row({space:6}){Circle({width:8,height:8}).fill(this.isRunning?'#4CAF50':'#F44336')Text(this.isRunning?'运行中':'已暂停').fontSize(12).fontColor(this.isRunning?'#4CAF50':'#F44336')}.layoutWeight(1).justifyContent(FlexAlign.End)}.width('100%')// 综合展示区域Column({space:10}){// 第一区:不同速度Text('速度梯度').fontSize(13).fontWeight(FontWeight.Medium).fontColor('#333333').width('100%')Row({space:6}){Text('慢').fontSize(10).fontColor('#FFFFFF').backgroundColor(PRESET_COLORS[0].value).padding(4).borderRadius(4)Marquee({start:this.isRunning,step:2,loop:-1,fromStart:true,src:'慢速滚动 - step=2'}).layoutWeight(1).height(28).fontSize(12).fontColor(PRESET_COLORS[0].value).backgroundColor('#E8F5E9').borderRadius(14)}.width('100%')Row({space:6}){Text('中').fontSize(10).fontColor('#FFFFFF').backgroundColor(PRESET_COLORS[1].value).padding(4).borderRadius(4)Marquee({start:this.isRunning,step:6,loop:-1,fromStart:true,src:'中速滚动 - step=6'}).layoutWeight(1).height(28).fontSize(12).fontColor(PRESET_COLORS[1].value).backgroundColor('#E3F2FD').borderRadius(14)}.width('100%')Row({space:6}){Text('快').fontSize(10).fontColor('#FFFFFF').backgroundColor(PRESET_COLORS[2].value).padding(4).borderRadius(4)Marquee({start:this.isRunning,step:12,loop:-1,fromStart:true,src:'快速滚动 - step=12'}).layoutWeight(1).height(28).fontSize(12).fontColor(PRESET_COLORS[2].value).backgroundColor('#FFF3E0').borderRadius(14)}.width('100%')// 第二区:不同样式Text('样式变化').fontSize(13).fontWeight(FontWeight.Medium).fontColor('#333333').width('100%')Marquee({start:this.isRunning,step:5,loop:-1,fromStart:true,src:'✨ 主题色大字风格 - HarmonyOS 跑马灯'}).width('100%').height(42).fontSize(17).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').backgroundColor(DEMO_THEME_COLOR).borderRadius(21)Marquee({start:this.isRunning,step:4,loop:-1,fromStart:true,src:'💎 描边风格 - 优雅的边框设计'}).width('100%').height(38).fontSize(14).fontColor(DEMO_THEME_COLOR).backgroundColor('#FFFFFF').border({width:2,color:DEMO_THEME_COLOR,radius:19})Marquee({start:this.isRunning,step:3,loop:-1,fromStart:true,src:'🌙 暗色风格 - 深色背景亮色文字'}).width('100%').height(38).fontSize(14).fontColor('#00E5FF').backgroundColor('#263238').borderRadius(19)// 第三区:循环模式Text('循环模式').fontSize(13).fontWeight(FontWeight.Medium).fontColor('#333333').width('100%')Row({space:6}){Text('无限').fontSize(10).fontColor(DEMO_SUBTEXT_COLOR).width(30)Marquee({start:this.isRunning,step:4,loop:-1,fromStart:true,src:'loop=-1 无限循环'}).layoutWeight(1).height(28).fontSize(12).fontColor('#333333').backgroundColor('#F5F5F5').borderRadius(14)}.width('100%')Row({space:6}){Text('3次').fontSize(10).fontColor(DEMO_SUBTEXT_COLOR).width(30)Marquee({start:this.isRunning,step:4,loop:3,fromStart:true,src:'loop=3 播放3次'}).layoutWeight(1).height(28).fontSize(12).fontColor('#333333').backgroundColor('#F5F5F5').borderRadius(14)}.width('100%')Row({space:6}){Text('1次').fontSize(10).fontColor(DEMO_SUBTEXT_COLOR).width(30)Marquee({start:this.isRunning,step:4,loop:1,fromStart:true,src:'loop=1 播放1次'}).layoutWeight(1).height(28).fontSize(12).fontColor('#333333').backgroundColor('#F5F5F5').borderRadius(14)}.width('100%')}.width('100%').padding(16).backgroundColor(DEMO_CARD_COLOR).borderRadius(12)}.alignItems(HorizontalAlign.Start)}Text('跑马灯综合示例 - 跑马灯综合示例').fontSize(12).fontColor('#999999').margin({top:12})}.width('100%').height('100%').backgroundColor(DEMO_BG_COLOR).padding(16)}}

收个尾

如果你最近正好要做 组件教学页、公告能力演示页、滚动信息模板页,那这篇可以直接当起步模板。先跑通,再替换数据和交互,效率会比从空白页起步高很多。