写点什么

HarmonyOS NEXT 跑马灯组件详解

作者:巴库一郎
  • 2025-05-13
    上海
  • 本文字数:4700 字

    阅读完需:约 15 分钟

HarmonyOS NEXT 跑马灯组件详解

(一): 组件概述与架构设计

效果演示

1. 组件简介

跑马灯(Marquee)组件是一个用于展示滚动文本的 UI 组件,主要用于处理文本内容超出显示区域时的展示问题。当文本内容过长时,组件会自动实现文本的循环滚动效果,并在每次循环结束后暂停一定时间。

2. 核心功能

  • 文本自动滚动展示

  • 支持自定义滚动速度和方向

  • 可配置滚动间隔和动画效果

  • 适配不同屏幕尺寸(手机/平板)

  • 支持自定义文本样式

3. 基础架构

整个跑马灯组件由以下几个主要部分组成:

@Componentexport struct MarqueeViewComponent {  // 主容器组件}@Componentstruct TripView {  // 行程信息容器}@Componentstruct TripMessage {  // 单条行程信息展示}@Componentexport struct FunctionDescription {  // 功能描述组件}
复制代码

4. 关键类和接口

4.1 动画配置类

export class MarqueeAnimationModifier {  iterations: number;    // 动画播放次数  duration: number;      // 动画持续时间  tempo: number;        // 动画播放速度  playMode: PlayMode;   // 播放模式  delayTime: number;    // 延迟时间}
复制代码

4.2 滚动配置类

export class MarqueeScrollModifier {  scrollWidth: Length;  // 滚动区域宽度  space: number;       // 文本间距}
复制代码

5. 组件层级结构

MarqueeViewComponent (根组件)├── FunctionDescription (功能描述)└── TripView (行程视图)    └── TripMessage (行程信息)        └── MarqueeSection (跑马灯核心组件)
复制代码

6. 使用场景

该组件特别适用于以下场景:

  • 新闻公告滚动展示

  • 长文本信息展示

  • 消息通知展示

  • 实时信息更新展示

7. 代码示例

基本使用方式:

MarqueeSection({  marqueeTextBuilder: () => {    this.marqueeTextBuilder(this.tripDataItem.ticketEntrance)  },  marqueeAnimationModifier: new MarqueeAnimationModifier(),  marqueeScrollModifier: new MarqueeScrollModifier(    display.isFoldable() ?     $r('app.string.marquee_scroll_phone_width') :     $r('app.string.marquee_scroll_tablet_width'),    Constants.BLANK_SPACE  )})
复制代码

8. 关键知识点解析

8.1 装饰器使用

  • @Component: 声明一个自定义组件

  • @State: 组件状态管理

  • @Builder: 自定义构建函数

8.2 响应式设计

  • 使用display.isFoldable()判断设备类型

  • 通过资源引用($r)实现不同设备适配

8.3 布局设计

  • 使用ColumnRow进行弹性布局

  • 通过RelativeContainer实现相对定位

9. 小结

跑马灯组件是一个功能完整、易于使用的 UI 组件,通过合理的架构设计和模块化的代码组织,使得组件具有良好的可维护性和扩展性。在后续的文章中,我们将深入探讨每个模块的具体实现细节。


(二): MarqueeSection 核心实现

效果演示



1. MarqueeSection 组件概述

MarqueeSection 是跑马灯组件的核心,负责实现文本的滚动效果。它通过配置动画参数和滚动属性,实现了流畅的文本滚动展示效果。

2. 核心配置类详解

2.1 MarqueeAnimationModifier 类

export class MarqueeAnimationModifier {  iterations: number;     // 动画循环次数  duration: number;       // 持续时间(ms)  tempo: number;         // 播放速度  playMode: PlayMode;    // 播放模式  delayTime: number;     // 延迟时间(ms)  constructor(    iterations: number = -1,                    // 默认无限循环    duration: number = Constants.ANIMATION_DURATION,    tempo: number = 1,                         // 默认速度    playMode: PlayMode = PlayMode.Reverse,     // 默认反向播放    delayTime: number = Constants.DELAY_TIME   // 默认延迟时间  ) {    // 初始化配置  }}
复制代码

参数说明:

  • iterations: -1 表示无限循环,0 表示不动画,正数表示具体循环次数

  • duration: 一次完整动画的持续时间

  • tempo: 动画速度系数,值越大速度越快

  • playMode: 控制滚动方向

  • delayTime: 每次滚动后的停顿时间

2.2 MarqueeScrollModifier 类

export class MarqueeScrollModifier {  scrollWidth: Length;    // 滚动区域宽度  space: number;         // 文本间距  constructor(    scrollWidth: Length = Constants.DEFAULT_SCROLL_WIDTH,    space: number = Constants.BLANK_SPACE  ) {    this.scrollWidth = scrollWidth;    this.space = space;  }}
复制代码

参数说明:

  • scrollWidth: 定义滚动区域的宽度,支持响应式配置

  • space: 定义文本之间的间隔距离

3. 组件使用示例

3.1 基础使用方式

MarqueeSection({  // 定义文本内容构建器  marqueeTextBuilder: () => {    this.marqueeTextBuilder(this.tripDataItem.ticketEntrance)  },  // 配置动画属性  marqueeAnimationModifier: new MarqueeAnimationModifier(),  // 配置滚动属性  marqueeScrollModifier: new MarqueeScrollModifier(    display.isFoldable() ?       $r('app.string.marquee_scroll_phone_width') :       $r('app.string.marquee_scroll_tablet_width'),    Constants.BLANK_SPACE  )})
复制代码

3.2 自定义文本构建器

@BuildermarqueeTextBuilder(marqueeText: ResourceStr) {  Text(marqueeText)    .fontSize(16)    .fontColor('#333333')    // 可以添加更多文本样式}
复制代码

4. 适配处理

4.1 设备类型适配

display.isFoldable() ?   $r('app.string.marquee_scroll_phone_width') : // 手机宽度  $r('app.string.marquee_scroll_tablet_width')  // 平板宽度
复制代码

4.2 资源引用

// 在resources目录下定义不同设备的宽度// phone.json{  "marquee_scroll_phone_width": "300vp"}// tablet.json{  "marquee_scroll_tablet_width": "500vp"}
复制代码

5. 动画效果实现

5.1 动画流程

  1. 初始化:文本位于起始位置

  2. 延迟:等待 delayTime 时间

  3. 滚动:按照设定的速度和方向滚动

  4. 停顿:完成一次滚动后暂停

  5. 循环:重复以上步骤

5.2 关键参数配置

const Constants = {  ANIMATION_DURATION: 8000,  // 动画持续8秒  DELAY_TIME: 1000,         // 延迟1秒  BLANK_SPACE: 100,         // 文本间距100  DEFAULT_SCROLL_WIDTH: '300vp'  // 默认滚动宽度}
复制代码

6. 性能优化

6.1 动态加载

使用 LazyForEach 实现数据的按需加载:

LazyForEach(this.tripData, (item: TripDataType) => {  TripMessage({    tripDataItem: item  })}, (item: TripDataType) => JSON.stringify(item))
复制代码

6.2 资源复用

通过 Builder 装饰器复用文本构建逻辑:

@BuildermarqueeTextBuilder(marqueeText: ResourceStr) {  Text(marqueeText)}
复制代码

7. 常见问题解决

  1. 文本不滚动

    检查 scrollWidth 是否合适

    确认 iterations 不为 0

    验证文本内容是否超出显示区域

  2. 滚动效果不流畅

    调整 duration 值

    优化 tempo 参数

    检查设备性能状态

  3. 适配问题

    使用响应式单位(vp)

    根据设备类型设置不同参数

    测试不同屏幕尺寸

8. 最佳实践

  1. 合理设置动画参数

  2. 注意性能优化

  3. 做好设备适配

  4. 保持代码简洁

  5. 遵循组件设计规范

通过以上详细讲解,相信你已经对 MarqueeSection 组件的实现原理和使用方法有了深入的了解。在实际开发中,可以根据具体需求调整相关参数,实现最佳的展示效果。

(三): 数据结构与状态管理

效果演示



1. 数据类型定义

1.1 行程数据类型

interface TripDataType {  trainNumber: string;      // 车次号  wholeCourse: string;      // 全程  startingTime: string;     // 出发时间  endingTime: string;       // 到达时间  origin: string;          // 始发站  destination: string;     // 终点站  timeDifference: string;  // 时间差  ticketEntrance: ResourceStr; // 票务入口  vehicleModel: string;    // 车型}
复制代码

1.2 常量定义

const Constants = {  ANGLE: 180,  ANIMATION_DURATION: 8000,  DELAY_TIME: 1000,  BLANK_SPACE: 100,  DEFAULT_SCROLL_WIDTH: '300vp'}
复制代码

2. 状态管理

2.1 组件状态声明

@Componentstruct TripView {  // 使用@State装饰器管理数据源状态  @State tripData: TripDataSource = new TripDataSource();}
复制代码

2.2 状态更新机制

  1. 自动更新:

// 当tripData发生变化时,组件会自动重新渲染this.tripData = new TripDataSource();
复制代码


  1. 数据绑定:

LazyForEach(this.tripData, (item: TripDataType) => {  TripMessage({    tripDataItem: item  })})
复制代码

3. 数据源实现

3.1 TripDataSource 类

export class TripDataSource implements IDataSource {  private tripList: TripDataType[] = [];    // 实现IDataSource接口的必要方法  totalCount(): number {    return this.tripList.length;  }    getData(index: number): TripDataType {    return this.tripList[index];  }}
复制代码

3.2 数据加载和更新

class TripDataSource {  // 初始化数据  constructor() {    this.loadData();  }  // 加载数据方法  private loadData() {    // 可以从服务器或本地加载数据    this.tripList = [      {        trainNumber: 'G1234',        wholeCourse: '北京-上海',        startingTime: '08:00',        endingTime: '13:00',        // ... 其他数据      }      // ... 更多数据    ];  }}
复制代码

4. 属性传递

4.1 组件属性定义

@Componentstruct TripMessage {  // 私有属性,用于接收父组件传递的数据  private tripDataItem: TripDataType = {} as TripDataType;}
复制代码

4.2 属性使用

TripMessage({  tripDataItem: item  // 传递数据给子组件})
复制代码

5. 状态同步

5.1 父子组件通信

@Componentstruct ParentComponent {  @State parentData: string = '';    build() {    ChildComponent({      data: this.parentData,      onDataChange: (newValue: string) => {        this.parentData = newValue;      }    })  }}
复制代码

5.2 状态监听

@Componentstruct ChildComponent {  @Prop data: string;  onDataChange: (value: string) => void;    build() {    // 使用传入的数据和回调  }}
复制代码

6. 性能优化

6.1 懒加载实现

LazyForEach(this.tripData, (item: TripDataType) => {  TripMessage({    tripDataItem: item  })}, (item: TripDataType) => JSON.stringify(item))
复制代码

6.2 数据缓存

class TripDataSource {  private cache: Map<string, TripDataType> = new Map();    getData(index: number): TripDataType {    const key = `trip_${index}`;    if (!this.cache.has(key)) {      this.cache.set(key, this.tripList[index]);    }    return this.cache.get(key);  }}
复制代码

7. 最佳实践

7.1 状态管理原则

  1. 最小化状态:只将必要的数据声明为状态

  2. 合理的状态粒度:避免过大或过小的状态

  3. 单一数据源:避免重复的状态声明

  4. 及时清理:不再需要的状态及时释放

7.2 数据处理建议

  1. 数据验证:

private validateTripData(data: TripDataType): boolean {  return data && data.trainNumber && data.wholeCourse;}
复制代码


  1. 错误处理:

try {  this.loadData();} catch (error) {  console.error('Failed to load trip data:', error);}
复制代码


  1. 数据转换:

private formatTripData(raw: any): TripDataType {  return {    trainNumber: raw.trainNumber || '',    wholeCourse: raw.wholeCourse || '',    // ... 其他字段处理  };}
复制代码


8. 调试技巧

8.1 状态监控

@State@Watch('onTripDataChange')tripData: TripDataSource = new TripDataSource();onTripDataChange() {  console.info('Trip data changed:', this.tripData);}
复制代码


8.2 性能分析

private measurePerformance() {  const start = performance.now();  // 执行操作  const end = performance.now();  console.info('Operation took:', end - start, 'ms');}
复制代码


通过以上详细的讲解,你应该已经掌握了跑马灯组件中数据结构和状态管理的核心概念。这些知识将帮助你更好地理解和使用该组件,同时也能够在开发类似组件时应用这些最佳实践。

用户头像

巴库一郎

关注

还未添加个人签名 2024-11-20 加入

还未添加个人简介

评论

发布
暂无评论
HarmonyOS NEXT 跑马灯组件详解_鸿蒙_巴库一郎_InfoQ写作社区