HarmonyOS 鸿蒙Next中如何实现Row组件及其子组件持续缩放效果?

HarmonyOS 鸿蒙Next中如何实现Row组件及其子组件持续缩放效果? 如何实现Row组件及其子组件持续缩放效果?

3 回复

方案一:使用 animateTo 实现持续缩放

@Entry
@Component
struct RowScaleAnimation {
  @State scaleValue: number = 1;
  private isAnimating: boolean = false;
  // 持续缩放动画
  startContinuousScale() {
    if (this.isAnimating) return;
    this.isAnimating = true;
    this.animateScale();
  }
  animateScale() {
    animateTo({
      duration: 1000,
      curve: Curve.EaseInOut,
      iterations: -1,   // -1 表示无限循环
      playMode: PlayMode.Alternate,   // 往返播放
      onFinish: () => {
        // 动画结束回调(无限循环时不会触发)
      }
    }, () => {
      this.scaleValue = this.scaleValue === 1 ? 1.2 : 1;
    })
  }
  build() {
    Column() {
      Row() {
        Text('Item 1')
          .fontSize(20)
          .margin(10)
        Text('Item 2')
          .fontSize(20)
          .margin(10)
        Text('Item 3')
          .fontSize(20)
          .margin(10)
      }
      .width('80%')
      .height(100)
      .backgroundColor(Color.Pink)
      .justifyContent(FlexAlign.SpaceAround)
      .scale({ x: this.scaleValue, y: this.scaleValue })  // 应用缩放
      Button('开始持续缩放')
        .onClick(() => {
          this.startContinuousScale();
        })
        .margin({ top: 20 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

方案二:使用 animation 修饰符实现

@Entry
@Component
struct RowScaleAnimationV2 {
  @State scaleValue: number = 1;
  private timer: number = -1;
  aboutToAppear() {
    // 页面加载时自动开始动画
    this.startAnimation();
  }
  aboutToDisappear() {
    // 清理定时器
    if (this.timer !== -1) {
      clearInterval(this.timer);
    }
  }
  startAnimation() {
    this.timer = setInterval(() => {
      // 在 1.0 和 1.2 之间切换
      this.scaleValue = this.scaleValue === 1 ? 1.2 : 1;
    }, 1000);
  }
  build() {
    Column() {
      Row() {
        Text('Item 1')
          .fontSize(20)
          .margin(10)
          .backgroundColor(Color.Orange)
          .padding(10)
        Text('Item 2')
          .fontSize(20)
          .margin(10)
          .backgroundColor(Color.Yellow)
          .padding(10)
        Text('Item 3')
          .fontSize(20)
          .margin(10)
          .backgroundColor(Color.Green)
          .padding(10)
      }
      .width('80%')
      .height(100)
      .backgroundColor(Color.Pink)
      .justifyContent(FlexAlign.SpaceAround)
      .scale({ x: this.scaleValue, y: this.scaleValue })
      .animation({
        duration: 1000,
        curve: Curve.EaseInOut,
        iterations: -1,  // 无限循环
        playMode: PlayMode.Alternate  // 往返播放
      })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

方案三:子组件独立缩放效果

@Entry
@Component
struct RowChildrenScaleAnimation {
  @State scale1: number = 1;
  @State scale2: number = 1;
  @State scale3: number = 1;
  aboutToAppear() {
    // 三个子组件错开时间开始缩放
    setTimeout(() => this.animateItem1(), 0);
    setTimeout(() => this.animateItem2(), 300);
    setTimeout(() => this.animateItem3(), 600);
  }
  animateItem1() {
    animateTo({
      duration: 1000,
      curve: Curve.EaseInOut,
      iterations: -1,
      playMode: PlayMode.Alternate
    }, () => {
      this.scale1 = this.scale1 === 1 ? 1.3 : 1;
    })
  }
  animateItem2() {
    animateTo({
      duration: 1000,
      curve: Curve.EaseInOut,
      iterations: -1,
      playMode: PlayMode.Alternate
    }, () => {
      this.scale2 = this.scale2 === 1 ? 1.3 : 1;
    })
  }
  animateItem3() {
    animateTo({
      duration: 1000,
      curve: Curve.EaseInOut,
      iterations: -1,
      playMode: PlayMode.Alternate
    }, () => {
      this.scale3 = this.scale3 === 1 ? 1.3 : 1;
    })
  }
  build() {
    Column() {
      Row() {
        Text('Item 1')
          .fontSize(20)
          .backgroundColor(Color.Orange)
          .padding(20)
          .borderRadius(10)
          .scale({ x: this.scale1, y: this.scale1 })
        Text('Item 2')
          .fontSize(20)
          .backgroundColor(Color.Yellow)
          .padding(20)
          .borderRadius(10)
          .scale({ x: this.scale2, y: this.scale2 })
          .margin({ left: 10, right: 10 })
        Text('Item 3')
          .fontSize(20)
          .backgroundColor(Color.Green)
          .padding(20)
          .borderRadius(10)
          .scale({ x: this.scale3, y: this.scale3 })
      }
      .width('90%')
      .justifyContent(FlexAlign.SpaceAround)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

方案四:呼吸式缩放(更平滑)

@Entry
@Component
struct RowBreathingAnimation {
  @State scaleValue: number = 1;
  aboutToAppear() {
    this.startBreathing();
  }
  startBreathing() {
    // 使用 animateTo 实现平滑的呼吸效果
    this.breatheIn();
  }
  breatheIn() {
    animateTo({
      duration: 1500,
      curve: Curve.Smooth,
      onFinish: () => {
        this.breatheOut();
      }
    }, () => {
      this.scaleValue = 1.15;
    })
  }
  breatheOut() {
    animateTo({
      duration: 1500,
      curve: Curve.Smooth,
      onFinish: () => {
        this.breatheIn();  // 循环
      }
    }, () => {
      this.scaleValue = 1;
    })
  }
  build() {
    Column() {
      Row() {
        Image($r('app.media.icon'))
          .width(50)
          .height(50)
        Text('呼吸式缩放')
          .fontSize(24)
          .margin({ left: 10 })
      }
      .width('80%')
      .height(100)
      .backgroundColor('#FFE6F0FF')
      .borderRadius(20)
      .justifyContent(FlexAlign.Center)
      .scale({ x: this.scaleValue, y: this.scaleValue })
      .shadow({
        radius: 20,
        color: '#40000000',
        offsetX: 0,
        offsetY: 5
      })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#F5F5F5')
  }
}

方案五:复杂波浪式缩放

@Entry
@Component
struct RowWaveScaleAnimation {
  @State scales: number[] = [1, 1, 1, 1, 1];
  private currentIndex: number = 0;
  aboutToAppear() {
    this.startWaveAnimation();
  }
  startWaveAnimation() {
    setInterval(() => {
      // 重置当前索引的缩放
      let newScales = [...this.scales];
      // 设置新的缩放值
      for (let i = 0; i < newScales.length; i++) {
        if (i === this.currentIndex) {
          newScales[i] = 1.4;
        } else {
          newScales[i] = 1;
        }
      }
      animateTo({
        duration: 300,
        curve: Curve.EaseInOut
      }, () => {
        this.scales = newScales;
      })
      // 移动到下一个
      this.currentIndex = (this.currentIndex + 1) % this.scales.length;
    }, 400);
  }
  build() {
    Column() {
      Row() {
        ForEach([0, 1, 2, 3, 4], (index: number) => {
          Text(`${index + 1}`)
            .fontSize(24)
            .fontWeight(FontWeight.Bold)
            .width(50)
            .height(50)
            .textAlign(TextAlign.Center)
            .backgroundColor(Color.Orange)
            .borderRadius(25)
            .scale({ x: this.scales[index], y: this.scales[index] })
            .margin(5)
        })
      }
      .width('100%')
      .justifyContent(FlexAlign.Center)
      Text('波浪式缩放效果')
        .fontSize(16)
        .margin({ top: 30 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

方案六:可控制的持续缩放

@Entry
@Component
struct ControllableRowScaleAnimation {
  @State scaleValue: number = 1;
  @State isAnimating: boolean = false;
  private animationTimer: number = -1;
  // 开始动画
  startAnimation() {
    if (this.isAnimating) return;
    this.isAnimating = true;
    this.animationTimer = setInterval(() => {
      animateTo({
        duration: 500,
        curve: Curve.EaseInOut
      }, () => {
        this.scaleValue = this.scaleValue === 1 ? 1.2 : 1;
      })
    }, 500);
  }
  // 停止动画
  stopAnimation() {
    if (!this.isAnimating) return;
    this.isAnimating = false;
    if (this.animationTimer !== -1) {
      clearInterval(this.animationTimer);
      this.animationTimer = -1;
    }
    // 恢复到原始大小
    animateTo({
      duration: 300,
      curve: Curve.EaseOut
    }, () => {
      this.scaleValue = 1;
    })
  }
  aboutToDisappear() {
    this.stopAnimation();
  }
  build() {
    Column() {
      // 动画目标
      Row() {
        Text('持续')
          .fontSize(20)
          .fontColor(Color.White)
        Text('缩放')
          .fontSize(20)
          .fontColor(Color.White)
          .margin({ left: 10 })
        Text('动画')
          .fontSize(20)
          .fontColor(Color.White)
          .margin({ left: 10 })
      }
      .width(200)
      .height(80)
      .backgroundColor(this.isAnimating ? Color.Red : Color.Blue)
      .borderRadius(10)
      .justifyContent(FlexAlign.Center)
      .scale({ x: this.scaleValue, y: this.scaleValue })
      // 控制按钮
      Row() {
        Button('开始缩放')
          .onClick(() => this.startAnimation())
          .enabled(!this.isAnimating)
          .backgroundColor(Color.Green)
          .margin({ right: 10 })
        Button('停止缩放')
          .onClick(() => this.stopAnimation())
          .enabled(this.isAnimating)
          .backgroundColor(Color.Orange)
      }
      .margin({ top: 50 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

关键参数说明

scale 属性

.scale({ x: number, // X 轴缩放比例 y: number, // Y 轴缩放比例 z?: number, // Z 轴缩放比例(3D) centerX?: number, // 缩放中心点 X 坐标 centerY?: number // 缩放中心点 Y 坐标 })

animation 参数

.animation({ duration: number, // 动画时长(毫秒) curve: Curve, // 动画曲线 delay?: number, // 延迟时间 iterations: number, // 迭代次数(-1 为无限) playMode: PlayMode, // 播放模式 tempo?: number, // 播放速度 onFinish?: () => void // 完成回调 })

PlayMode 选项

  • PlayMode.Normal - 正常播放
  • PlayMode.Reverse - 反向播放
  • PlayMode.Alternate - 往返播放(推荐用于持续缩放)
  • PlayMode.AlternateReverse - 反向往返播放

Curve 动画曲线

  • Curve.Linear - 线性
  • Curve.EaseInOut - 缓入缓出(推荐)
  • Curve.Smooth - 平滑(推荐用于呼吸效果)
  • Curve.FastOutSlowIn - 快出慢入
  • Curve.Friction - 阻尼

更多关于HarmonyOS 鸿蒙Next中如何实现Row组件及其子组件持续缩放效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,使用Row组件结合animation属性实现持续缩放效果。通过scale动画类型设置目标缩放值,例如{ scale: { x: 1.2, y: 1.2 } }。配置动画参数duration(时长)、iterations(迭代次数,-1表示无限循环)和easing(缓动函数)。将动画绑定到Row或其子组件的animation属性即可实现自动持续缩放。

在HarmonyOS Next中,可以通过animateTo结合插值计算实现Row及其子组件的持续缩放效果。以下是一个核心实现示例:

// 引入必要模块
import { Curves } from '@kit.ArkUI';

@Entry
@Component
struct ScaleAnimationExample {
  @State scaleValue: number = 1.0;

  aboutToAppear() {
    // 启动循环动画
    this.startContinuousScale();
  }

  startContinuousScale() {
    // 使用animateTo实现缩放动画循环
    animateTo({
      duration: 1000, // 动画时长1秒
      curve: Curves.EaseInOut, // 缓动曲线
      iterations: -1, // 无限循环
      playMode: PlayMode.Alternate // 交替播放
    }, () => {
      this.scaleValue = this.scaleValue === 1.0 ? 0.5 : 1.0; // 在1.0和0.5之间切换
    })
  }

  build() {
    Row() {
      // 子组件示例
      Text('缩放内容')
        .fontSize(20)
        .fontColor(Color.White)
        .backgroundColor(Color.Blue)
        .padding(10)
    }
    .scale({ x: this.scaleValue, y: this.scaleValue }) // 应用缩放
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

关键点说明:

  1. 使用animateTo动画API,设置iterations: -1实现无限循环
  2. 通过PlayMode.Alternate使缩放值在1.0和0.5之间来回切换
  3. scale修饰符应用缩放变换到Row容器
  4. 子组件会自动继承容器的缩放效果

可通过调整duration控制动画速度,修改curve改变动画缓动效果。

回到顶部