鸿蒙 使用动画 简单使用

发布于:2025-05-10 ⋅ 阅读:(4) ⋅ 点赞:(0)

鸿蒙 使用动画 简单使用

动画就两个,属性动画转场动画

属性动画只是组件的属性发生变化,而转场动画是指对将要出现消失的组件做动画,而文档的其他动画只是给这两个动画效果锦上添花罢了

这篇文章简单介绍这两个动画,其他的看文档去吧

属性动画

以下是三种 ArkUI 属性动画接口的对比表格,用通俗语言解释它们的核心差异:

对比维度 animateTo animation keyframeAnimateTo
功能定位 打包式动画(集体行动) 贴标签式动画(各自为战) 里程碑式动画(分阶段闯关)
典型场景 多个属性同步变化(如按钮点击缩放+变色) 不同属性独立动画(如颜色渐变 1 秒,缩放 0.5 秒) 复杂多阶段动画(如加载进度条分段变速)
代码结构 包裹在闭包内的属性集合 链式附加在属性后 定义关键帧数组 + 全局参数
动画控制 统一时长/曲线 每个属性独立设置参数 每个阶段独立设置时长/曲线
阶段数量 单一阶段 单一阶段 多阶段(通过数组定义多个关键帧)
曲线独立性 全局统一曲线 属性独立曲线 阶段独立曲线
延迟/循环控制 仅支持全局延迟 无内置延迟/循环 支持全局延迟、循环次数(含无限循环)
嵌套能力 支持多层嵌套动画 不支持嵌套 可与其他动画组合使用
性能优化建议 优先用transform代替布局属性 同左 避免频繁改变布局属性
通俗类比 交响乐团(统一指挥) 独奏演员(各自演奏) 电影分镜(按剧本分段表演)
一句话选择指南
  • 想让多个属性整齐划一变化 → animateTo
  • 想让不同属性各玩各的animation
  • 需要分步骤、变速的复杂动画 → keyframeAnimateTo
animateTo
animateTo(value: AnimateParam, event: () => void): void
  • value 指定 AnimateParam 对象(包括时长、Curve 等)
  • event 为动画的闭包函数

示例:点击后一个从左向右滚 90° 的方块且颜色变半透明

import { curves } from '@kit.ArkUI';

@Entry
@Component
struct AnimateToDemo {
  @State animate: boolean = false;
  // 第一步: 声明相关状态变量
  @State rotateValue: number = 0; // 旋转角度
  @State translateX: number = 0; // 偏移量
  @State opacityValue: number = 1; // 透明度

  // 第二步:将状态变量设置到相关可动画属性接口
  build() {
    Row() {
      Column() {
      }
      .width(100)
      .height(100)
      .backgroundColor('#D94838')
      .borderRadius(30)
      .opacity(this.opacityValue)
      .translate({ x: this.translateX })
      .rotate({ angle: this.rotateValue })
    }
    .onClick(() => {
      // 直接使用animateTo可能导致实例不明确的问题,建议使用getUIContext获取UIContext实例
      // 第三步:调用 keyframeAnimateTo 接口
      this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => {
        this.animate = !this.animate;
        // 旋转角度发生变化
        this.rotateValue = this.animate ? 90 : 0;
        // 透明度发生变化
        this.opacityValue = this.animate ? 0.6 : 1;
        // 位置属性发生变化
        this.translateX = this.animate ? 50 : 0;
      })
    })
  }
}
animation

把 animation 接口加在要做属性动画的可动画属性后即可

示例:点击后一个从左向右滚 90° 的方块且颜色变半透明

import { curves } from '@kit.ArkUI';

@Entry
@Component
struct AnimationDemo {
  @State animate: boolean = false;
  // 第一步: 声明相关状态变量
  @State rotateValue: number = 0; // 旋转角度
  @State translateX: number = 0; // 偏移量
  @State opacityValue: number = 1; // 透明度

  // 第二步:将状态变量设置到相关可动画属性接口
  build() {
    Row() {
      Column() {
      }
      .width(100)
      .height(100)
      .backgroundColor('#D94838')
      .borderRadius(30)
      .opacity(this.opacityValue)
      .translate({ x: this.translateX })
      // 第三步:通过属性动画接口开启属性动画
      .rotate({ angle: this.rotateValue })
      .animation({ curve: curves.springMotion() })// 这里和animateTo的不同,直接加
      .onClick(() => {
        this.animate = !this.animate;
        // 第四步:闭包内通过状态变量改变UI界面
        // 这里可以写任何能改变UI的逻辑比如数组添加,显隐控制,系统会检测改变后的UI界面与之前的UI界面的差异,对有差异的部分添加动画
        // 组件一的rotate属性发生变化,所以会给组件一添加rotate旋转动画
        this.rotateValue = this.animate ? 90 : 0;
        // 组件二的translate属性发生变化,所以会给组件二添加translate偏移动画
        this.translateX = this.animate ? 50 : 0;
        // 父组件column的opacity属性有变化,会导致其子节点的透明度也变化,所以这里会给column和其子节点的透明度属性都加动画
        this.opacityValue = this.animate ? 0.6 : 1;
      })
    }
  }
}
keyframeAnimateTo
keyframeAnimateTo(param: KeyframeAnimateParam, keyframes: Array<KeyframeState>): void

keyframeAnimateTo 接口参数中,第一个参数 KeyframeAnimateParam 为关键帧动画的整体参数(包括延时、播放次数、结束回调、期望帧率),第二个参数是一个数组,每一项表示一个关键帧内的动画行为;每一段动画可单独控制动画参数(包括时长、Curve 等)。

示例:点击后一个从左向右滚 90° 的方块且颜色变半透明,又滚回去且无限循环

@Entry
@Component
struct KeyframeAnimateToDemo {
  // 第一步: 声明相关状态变量
  @State rotateValue: number = 0; // 逆时针旋转90度恢复至0度
  @State translateX: number = 0; // 偏移量
  @State opacityValue: number = 1; // 透明度

  // 第二步:将状态变量设置到相关可动画属性接口
  build() {
    Row() {
      Column() {
      }
      .width(100)
      .height(100)
      .backgroundColor('#D94838')
      .borderRadius(30)
      .opacity(this.opacityValue)
      .translate({ x: this.translateX })
      .rotate({ angle: this.rotateValue })
      .onClick(() => {
        this.getUIContext()?.keyframeAnimateTo({
          iterations: -1, // 无限循环
        }, [
          {
            // 第一段关键帧动画时长为800ms,顺时针旋转90度,透明度变从1变为0.6,translate从0位移到50
            duration: 800,
            event: () => {
              this.rotateValue = 90;
              this.opacityValue = 0.6;
              this.translateX = 50;
            }
          },
          {
            // 第二段关键帧动画时长为500ms,逆时针旋转90度恢复至0度,透明度变从0.6变为1,translate从50位移到0
            duration: 500,
            event: () => {
              this.rotateValue = 0;
              this.opacityValue = 1;
              this.translateX = 0;
            }
          }
        ]);
      })
    }
  }
}

转场动画

文档太他妈多了,我就说下面这个吧

出现/消失转场:对新增、消失的控件实现动画效果
  • transition 是基础的组件转场接口,用于实现一个组件出现或者消失时的动画效果
  • 可以通过 TransitionEffect 对象的组合使用,定义出各式效果。

分三步写:

  1. 创建 TransitionEffect
  2. 将转场效果通过 transition 接口设置到组件
  3. 新增或者删除组件触发转场

示例:点击边框后组件跑了,组件跑的姿势很多

import { curves } from '@kit.ArkUI';

@Entry
@Component
struct TransitionEffectDemo {
  @State isPresent: boolean = false;
  // 第一步,创建 TransitionEffect
  private effect: TransitionEffect =
    // 创建默认透明度转场效果,并指定了springMotion(0.6, 0.8)曲线
    TransitionEffect.OPACITY.animation({
      curve: curves.springMotion(0.6, 0.8)
    })// 通过combine方法,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion(0.6, 0.8)
      .combine(TransitionEffect.scale({
        x: 0,
        y: 0
      }))// 添加旋转转场效果,这里的动画参数会跟随上面带animation的TransitionEffect,也就是springMotion(0.6, 0.8)
      .combine(TransitionEffect.rotate({ angle: 90 }))// 添加平移转场效果,这里的动画参数使用指定的springMotion()
      .combine(TransitionEffect.translate({ y: 150 })
        .animation({ curve: curves.springMotion() }))// 添加move转场效果,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion()
      .combine(TransitionEffect.move(TransitionEdge.END));

  build() {
    Stack() {
      if (this.isPresent) {
        Column() {
          Text('ArkUI')
            .fontWeight(FontWeight.Bold)
            .fontSize(20)
            .fontColor(Color.White)
        }
        .justifyContent(FlexAlign.Center)
        .width(150)
        .height(150)
        .borderRadius(10)
        .backgroundColor(0xf56c6c)
        // 第二步:将转场效果通过transition接口设置到组件
        .transition(this.effect)
      }

      // 边框
      Column()
        .width(155)
        .height(155)
        .border({
          width: 5,
          radius: 10,
          color: Color.Black
        })
    }
    // 第三步:新增或者删除组件触发转场,控制新增或者删除组件
    .onClick(() => {
      this.isPresent = !this.isPresent;
    })
  }
}

写个第二象限的抛物线球形运动轨迹

@Entry
@Component
struct Index {
  @State x: number = 0

  ani() {
    this.x -= 5
    if (this.x <= -200) {
      this.x = 0
    }
  }

  build() {
    Row()
      .width(50)
      .height(50)
      .borderRadius(25)
      .margin({ top: 300, left: 200 })
      .backgroundColor('#AAA')
      .translate({ x: this.x, y: -0.005 * this.x * this.x })
      .animation({
        duration: 10, curve: 'linear', onFinish: () => {
          this.ani()
        }
      })
      .onClick(_ => {
        this.x = -1
      })
  }
}

轨迹类似这种:从原点向上走
在这里插入图片描述

说明: translate 的值涉及到抛物线函数,y=ax^2+bx+c,就是抛物线函数
当b和c都为零时,就是从原点开始,y=a*x^2
在屏幕坐标系中,y 轴的正方向是向下的(与数学坐标系相反)
所以,x取负值this.x -= 5,y也要取负值y: -0.005 * this.x * this.x,才会保持曲线在坐标的第二象限


网站公告

今日签到

点亮在社区的每一天
去签到