如何实现文字表面移动光线效果
==============

#### 问题现象

使用Text组件时，如何给文字表面添加移动光线效果？

#### 背景知识

*   [linearGradient](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-gradient-color#lineargradient)：颜色线性渐变。可设置线性渐变的起始角度、线性渐变的方向、多种颜色渐变。
*   [BlendMode](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-graphics-drawing-e#blendmode)：混合模式枚举。混合模式会将两种颜色（源色、目标色）以特定的方式混合生成一种新的颜色，通常用于叠加、滤镜和遮罩等图形操作场景。
*   [setInterval](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-timer#setinterval)：重复调用一个函数，在每次调用之间具有固定的时间延迟。
*   [显式动画 (animateTo)](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-explicit-animation)：提供全局animateTo显式动画接口来指定由于闭包代码导致的状态变化插入过渡动效。同属性动画，布局类改变宽高的动画，内容都是直接到终点状态，例如文字、[Canvas](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-components-canvas-canvas)的内容等，如果要内容跟随宽高变化，可以使用[renderFit](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-renderfit#renderfit)属性配置。

#### 解决方案

*   方案逻辑：通过渐变色模拟光线，Text组件本身不支持渐变色，需要在父组件添加渐变色后，与Text组件混合来实现文字渐变色，然后通过移动渐变色所在位置，实现光线移动效果。
    
    1.  创建初始文字，设置字体颜色。
        
        Text(this.message)
          .onClick(() => {
            this.message = this.message + '1';
          })
          .maxLines(1)
          .fontSize(40)
          .fontWeight(800)
          .fontColor(Color.White)
        
    2.  在父组件添加渐变色，设置三个颜色起始点，中间点为光线颜色，两边点为字体颜色。
        
        .linearGradient({
          angle: 110,
          colors: \[\[Color.White, this.leftlocation\], \[Color.Orange, this.location\],
            \[Color.White, this.rightlocation\]\] _// 设置渐变色起始点位_
        })
        
    3.  设置融合模式为DST\_IN，仅保留目标像素与源不透明部分的交集。
        
        .blendMode(BlendMode.DST\_IN, BlendApplyType.OFFSCREEN) _// 设置混合模式_
        
    4.  通过setInterval设置三个渐变色点位的周期性运动，实现光线移动效果。
        
        aboutToAppear(): void {
          setInterval(() => {
            this.location += 0.01;
            this.leftlocation += 0.01;
            this.rightlocation += 0.01;
            if (this.location >= 1) {
              this.location = 0.0;
              this.leftlocation = -0.1;
              this.rightlocation = 0.1;
            }
          }, 50);
        }
        
        效果预览：
        
        ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/28/v3/iT-s1CIVSM-64bVMwmSF0w/zh-cn_image_0000002658913723.png?HW-CC-KV=V1&HW-CC-Date=20260709T133909Z&HW-CC-Expire=86400&HW-CC-Sign=65543504E18750CDD2F279BD091EA980D08DEE9EEA8B0F5CE1419C92D6B448B9 "点击放大")
        
    
    完整示例参考如下：
    
    @Entry
    @Component
    struct LightWord {
      @State message: string = 'Hello World';
      @State location: number = 0.0;
      @State leftlocation: number = -0.1;
      @State rightlocation: number = 0.1;
    
      _// 配置渐变色起始点位周期性移动_
      aboutToAppear(): void {
        setInterval(() => {
          this.location += 0.01;
          this.leftlocation += 0.01;
          this.rightlocation += 0.01;
          if (this.location >= 1) {
            this.location = 0.0;
            this.leftlocation = -0.1;
            this.rightlocation = 0.1;
          }
        }, 50);
      }
    
      build() {
        Column({ space: 5 }) {
          Row() {
            Text(this.message)
              .onClick(() => {
                this.message = this.message + '1';
              })
              .maxLines(1)
              .fontSize(40)
              .fontWeight(800)
              .fontColor(Color.White)
              .padding(10)
              .blendMode(BlendMode.DST\_IN, BlendApplyType.OFFSCREEN) _// 设置混合模式_
          }
          .linearGradient({
            angle: 110,
            colors: \[\[Color.White, this.leftlocation\], \[Color.Orange, this.location\],
              \[Color.White, this.rightlocation\]\] _//_ _设置渐变色起始点位_
          })
          .blendMode(BlendMode.SRC\_OVER, BlendApplyType.OFFSCREEN)
        }
        .width('100%')
        .height('100%')
        .backgroundColor(Color.Black)
        .justifyContent(FlexAlign.Center)
        .expandSafeArea(\[SafeAreaType.SYSTEM\], \[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM\])
      }
    }
    
*   若需实现类似跑马灯的循环颜色流动效果，可以通过结合animateTo，先重置渐变位置的状态，然后将渐变的起始颜色与终止颜色进行互换，最后使用递归实现循环。
    
    效果预览：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/2d/v3/CDOz2HDFSpmYd8ND9nfLvQ/zh-cn_image_0000002628394510.png?HW-CC-KV=V1&HW-CC-Date=20260709T133909Z&HW-CC-Expire=86400&HW-CC-Sign=33F43CF65FEB5F601866034F8783AF3BF27D4D313CDBDA1D3FA6355CD5190D32 "点击放大")
    
    完整示例参考如下：
    
    @Entry
    @Component
    struct Index {
      @State gradientPosition: number = 0;
      textContent: string = '生活就像海洋，只有意志坚强的人';
      COLOR\_START: Color = Color.Yellow;
      COLOR\_END: Color = Color.Blue;
    
      build() {
        Column() {
          Stack() {
            Text(this.textContent + this.textContent)
              .blendMode(BlendMode.DST\_IN, BlendApplyType.OFFSCREEN)
              .fontSize(30)
              .fontWeight(FontWeight.Bold)
          }
          .blendMode(BlendMode.SCREEN, BlendApplyType.OFFSCREEN)
          .linearGradient({
            angle: 135,
            colors: \[
              \[this.COLOR\_START, 0\],
              \[this.COLOR\_END, this.gradientPosition\],
              \[this.COLOR\_START, 1\],
            \]
          })
        }
        .width('100%')
        .height('100%')
        .backgroundColor(Color.Black)
        .expandSafeArea(\[SafeAreaType.SYSTEM\], \[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM\])
        .onAppear(() => {
          this.animateStart();
        })
      }
    
      private animateStart() {
        this.getUIContext().animateTo({
          duration: 3000,
          curve: Curve.Linear,
          iterations: 1,
          onFinish: () => {
            this.gradientPosition = 0;
            const COLOR\_START = this.COLOR\_START;
            const COLOR\_END = this.COLOR\_END;
         _   // 互换起始与终点的颜色_
            this.COLOR\_START = COLOR\_END;
            this.COLOR\_END = COLOR\_START;
            this.animateStart();
          }
        }, () => {
         _ // 启动动画：修改gradientPosition触发渐变移动_
          this.gradientPosition = 1;
        });
      }
    }