鸿蒙开发:简单了解属性动画

前言

什么是属性动画呢?字面之义就是让属性产生动画,产生某些可执行的动作,使其和原有的UI形态发生了根本的变化,当然了,其本身也类似这层意思;属性动画中,我们需要知道,并不是所有的属性都可以执行动画操作,比如一个组件,设置焦点控制,禁用控制,改变的只是动作状态,而本身的UI形态并没有发生变化,所以并不能执行动画,也就不属于动画属性。

是否定义为一个可执行动画属性,有两个标准,第一个是改变它能够使其UI发生变化,比如宽高,内边距,外边距属性,第二就是,改变它,可以添加动画作为过渡,不做动画,又何谈属性动画呢,是吧。

常见的可执行动画属性,如下:

分类 说明
布局属性 位置、大小、内边距、外边距、对齐方式、权重等。
仿射变换 平移、旋转、缩放、锚点等。
背景 背景颜色、背景模糊等。
内容 文字大小、文字颜色,图片对齐方式、模糊等。
前景 前景颜色等。
Overlay Overlay属性等。
外观 透明度、圆角、边框、阴影等。

实现属性动画

属性动画最注重的就是两点,一是必须使其UI发生改变,二是能够有动画产生连续效果,目前在鸿蒙开发中,系统提供了两个可以实现属性动画的方式,使用animateTo和animation来实现。

简单举例:

使用animateTo让组件平移100,动画持续时间为1秒。

TypeScript 复制代码
@Entry
@Component
struct Index {
  @State translateX: number = 0

  build() {
    Column() {
      Text("1")
        .width(50)
        .height(50)
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.Red)
        .translate({ x: this.translateX })

      Button("点击")
        .margin({ top: 10 })
        .onClick(() => {
          this.getUIContext()?.animateTo({ duration: 1000 }, () => {
            this.translateX = 100 //x轴移动100
          })
        })
    }
    .height('100%')
    .width('100%')
  }
}

使用animation让组件平移100,动画持续时间为1秒。

TypeScript 复制代码
@Entry
@Component
struct Index {
  @State translateX: number = 0

  build() {
    Column() {
      Text("1")
        .width(50)
        .height(50)
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.Red)
        .translate({ x: this.translateX })
        .animation({duration:1000})

      Button("点击")
        .margin({ top: 10 })
        .onClick(() => {
          this.translateX = 100 //x轴移动100
        })
    }
    .height('100%')
    .width('100%')
  }
}

可以看到实际效果是一样的。

当然了,除了平移属性能够实现这种效果,其实你使用margin也能实现平移的效果。

TypeScript 复制代码
 .margin({ left: this.translateX })
.animation({ duration: 1000 })

说明

需要说明的是,实现一个动画,无论是使用animation还是animateTo都是触发的动作,真正展示视觉效果,还得是可执行的属性,无论平移,缩放还是旋转。

平移动画

让一个组件产生一个平移动画,设置translate 属性即可,当然,你设置offset或者margin也是可以实现的,只不过 一个是组件偏移,一个是位置的坐标偏移,我理解是大差不差的,但是还是建议使用官方的translate。


其类型参数是TranslateOptions,接收三个参数,x,y,z,分别表示在对应轴移动的距离,值为正时表示向对应轴的正向移动,值为负时表示向对应轴的反向移动。

如果你仅仅是平移,只需要XY两个值即可,因为Z值有接近观察点放大和远离观察点缩小效果,一般未有缩放效果,Z值我们可以不传递。

例如,向X轴方向平移100,向Y轴方向平移100。

TypeScript 复制代码
@Entry
@Component
struct Index {
  @State translateX: number = 0
  @State translateY: number = 0

  build() {
    RelativeContainer() {

      Text("1")
        .width(50)
        .height(50)
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.Red)
        .translate({ x: this.translateX, y: this.translateY })
        .animation({ duration: 1000 })

      Button("点击")
        .onClick(() => {
          this.translateX = 100
          this.translateY = 100
        })
        .alignRules({
          center: { anchor: "__container__", align: VerticalAlign.Center },
          middle: { anchor: "__container__", align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}

效果:

如果你要加上Z值,比如也设置100,我们就会看到明显的缩放动画。

缩放动画

缩放动画,可以使用scale属性进行实现,类型参数为ScaleOptions,有五个参数,分别为X,Y,Z,centerX和centerY,X轴、Y轴、Z轴为缩放比例,默认值为1,centerX和centerY为设置缩放的中心点。

简单举例,原有基础之上放大2倍。

TypeScript 复制代码
@Entry
@Component
struct Index {
  @State translateX: number = 1
  @State translateY: number = 1
  @State translateZ: number = 1

  build() {
    RelativeContainer() {

      Text("1")
        .width(50)
        .height(50)
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.Red)
        .scale({ x: this.translateX, y: this.translateY, z: this.translateZ })
        .animation({ duration: 1000 })
        .margin({ top: 100 })
        .alignRules({
          top: { anchor: "__container__", align: VerticalAlign.Top },
          middle: { anchor: "__container__", align: HorizontalAlign.Center }
        })

      Button("点击")
        .margin({ top: 10 })
        .onClick(() => {
          this.translateX = 2
          this.translateY = 2
          this.translateZ = 2
        })
        .alignRules({
          center: { anchor: "__container__", align: VerticalAlign.Center },
          middle: { anchor: "__container__", align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}

效果查看:

默认系数为1,放大就比1大,缩小就比1小,centerX和centerY就是中心点,默认是组件的中点,如下图,放大两倍后,也是以中点放大两倍。

如果你更改了centerX和centerY的值,再放大时就是以更改的值作为中心点进行放大,可以看到是有明显的区别的。

旋转动画

旋转动画,可以使用rotate属性进行实现,类型参数为RotateOptions,总共有8个参数,详细介绍如下:

名称 类型 必填 说明
x number 旋转轴向量x坐标。
y number 旋转轴向量y坐标。
z number 旋转轴向量z坐标。
angle number / string 旋转角度。取值为正时相对于旋转轴方向顺时针转动,取值为负时相对于旋转轴方向逆时针转动。取值可为string类型,如'90deg'。
centerX number / string 变换中心点x轴坐标。表示组件变换中心点(即锚点)的x方向坐标。单位:vp
centerY number / string 变换中心点y轴坐标。表示组件变换中心点(即锚点)的y方向坐标。单位:vp
centerZ10+ number z轴锚点,即3D旋转中心点的z轴分量。
perspective10+ number 视距,即视点到z=0平面的距离。旋转轴和旋转中心点都基于坐标系设定,组件发生位移时,坐标系不会随之移动。

正常的旋转,我们只改变角度即可,也就是按照中心点旋转,比如旋转180度。

TypeScript 复制代码
@Entry
@Component
struct Index {
  @State angle: number = 0

  build() {
    RelativeContainer() {

      Text("1")
        .width(50)
        .height(50)
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.Red)
        .rotate({ angle: this.angle})
        .animation({ duration: 1000 })
        .margin({ top: 100 })
        .alignRules({
          top: { anchor: "__container__", align: VerticalAlign.Top },
          middle: { anchor: "__container__", align: HorizontalAlign.Center }
        })

      Button("点击")
        .margin({ top: 10 })
        .onClick(() => {
          this.angle = 180
        })
        .alignRules({
          center: { anchor: "__container__", align: VerticalAlign.Center },
          middle: { anchor: "__container__", align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}

效果查看:

当然了,你也可以通过改变中心点,或者坐标点,实现想要的旋转效果。

组合动画

单一动画,我们设置单个可执行属性即可,如果是多个动画,显而易见,就是设置多个属性,比如实现一个,X轴移动100,并且旋转180度,放大1.5倍。

TypeScript 复制代码
@Entry
@Component
struct Index {
  @State angle: number = 0
  @State translateX: number = 0
  @State scaleX: number = 1
  @State scaleY: number = 1
  @State scaleZ: number = 1

  build() {
    RelativeContainer() {

      Text("1")
        .width(50)
        .height(50)
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.Red)
        .rotate({ angle: this.angle })
        .translate({ x: this.translateX })
        .scale({ x: this.scaleX, y: this.scaleY, z: this.scaleZ })
        .animation({ duration: 1000 })
        .margin({ top: 100 })
        .alignRules({
          top: { anchor: "__container__", align: VerticalAlign.Top },
          middle: { anchor: "__container__", align: HorizontalAlign.Center }
        })

      Button("点击")
        .margin({ top: 10 })
        .onClick(() => {
          this.translateX = 100
          this.angle = 180
          this.scaleX = 1.5
          this.scaleY = 1.5
          this.scaleY = 1.5
        })
        .alignRules({
          center: { anchor: "__container__", align: VerticalAlign.Center },
          middle: { anchor: "__container__", align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}

效果查看

两种属性动画介绍

无论是是使用animateTo还是animation,其实最终要改变的都是组件的可执行属性,最终的效果是一致的,animateTo是闭包内改变属性引起的界面变化,一般作用于出现消失转场,而animation则是组件通过属性接口绑定的属性变化引起的界面变化,一般使用场景为,animateTo适用对多个可动画属性配置相同动画参数的动画,需要嵌套使用动画的场景;animation适用于对多个可动画属性配置不同参数动画的场景。

相关总结

如果你要执行动画的组件,是始终存在的,那么这种情况下,是推荐使用的,如果是那种将要出现或者将要消失的组件,这里是不推荐的。

还有就是,要合理的使用属性动画,避免一些轮询机制中使用,否则会影响其它页面的组件展示效果。

相关推荐
Freerain991 小时前
鸿蒙Next ArkTS语法适配背景概述
华为·harmonyos
他的猫哎1 小时前
鸿蒙 Navigation组件下的组件获取pageStack问题
harmonyos·鸿蒙
雨汨1 小时前
鸿蒙之路的坑
华为·harmonyos
轻口味2 小时前
【每日学点鸿蒙知识】沙箱目录、图片压缩、characteristicsArray、gm-crypto 国密加解密、通知权限
pytorch·华为·harmonyos
mmsx2 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
众拾达人5 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
xo198820116 小时前
鸿蒙人脸识别
redis·华为·harmonyos
吃着火锅x唱着歌6 小时前
PHP7内核剖析 学习笔记 第四章 内存管理(1)
android·笔记·学习
塞尔维亚大汉7 小时前
【OpenHarmony】 鸿蒙 UI开发之CircleIndicator
harmonyos·arkui
BisonLiu7 小时前
华为仓颉鸿蒙HarmonyOS NEXT仓颉原生数据网络HTTP请求(ohos.net.http)
harmonyos