动画

292 阅读4分钟

属性动画

为了那些改变属性,不那么生硬,有点动画 属性接口(以下简称属性)包含尺寸属性、布局属性、位置属性等多种类型

  • 布局属性 | 位置、大小、内边距、外边距、对齐方式、权重等。
  • 平移、旋转、缩放、锚点等
  • 文字大小、文字颜色,图片对齐方式、模糊等。
  • 外观 | 透明度、圆角、边框、阴影等

插补器

还有弹簧的

curves.responsiveSpringMotion(1, 0.25))
curves.springMotion()
Linear表示动画从头到尾的速度都是相同的。
Ease表示动画以低速开始,然后加快,在结束前变慢,CubicBezier(0.25, 0.1, 0.25, 1.0)。
EaseIn表示动画以低速开始,CubicBezier(0.42, 0.0, 1.0, 1.0)。
EaseOut表示动画以低速结束,CubicBezier(0.0, 0.0, 0.58, 1.0)。
EaseInOut表示动画以低速开始和结束,CubicBezier(0.42, 0.0, 0.58, 1.0)。
FastOutSlowIn标准曲线,CubicBezier(0.4, 0.0, 0.2, 1.0)。
LinearOutSlowIn减速曲线,CubicBezier(0.0, 0.0, 0.2, 1.0)。
FastOutLinearIn加速曲线,CubicBezier(0.4, 0.0, 1.0, 1.0)。
ExtremeDeceleration急缓曲线,CubicBezier(0.0, 0.0, 0.0, 1.0)。
Sharp锐利曲线,CubicBezier(0.33, 0.0, 0.67, 1.0)。
Rhythm节奏曲线,CubicBezier(0.7, 0.0, 0.2, 1.0)。
Smooth平滑曲线,CubicBezier(0.4, 0.0, 0.4, 1.0)。
Friction阻尼曲线,CubicBezier(0.2, 0.0, 0.2, 1.0)。

使用animateTo产生属性动画

// 改变刷行的方法
changeAnimate(){
  animateTo({ duration: 1000, curve: curves.springMotion() }, () => {
    if (this.scaleImage == 1) {
      this.scaleImage = 0.4
      this.translateImage = 100
      this.angleImage = 45
    } else {
      this.scaleImage = 1
      this.translateImage = 0
      this.angleImage = 0
    }
  })
}

使用animation产生属性动画

@State radius: number = 0
@State widthText: number = 150
@State opacityText: number = 1
@State heightText: number = 100
@State fontSizeText: number = 25
@State scaleImage: number = 1
@State translateImage: number = 0
@State angleImage: number = 0

build() {
  Column() {
    Text('大哥好')
      .borderRadius(this.radius)
      .borderColor(Color.Red)
      .fontSize(this.fontSizeText)
      .width(this.widthText)
      .height(this.heightText)
      .opacity(this.opacityText)
      .animation({ duration: 1000, curve: curves.springMotion() })
      .textAlign(TextAlign.Center)
      .borderWidth(2)
      .onClick(() => {
        if (this.radius == 0) {
          this.radius = 50
          this.widthText = 100
          this.heightText = 50
          this.fontSizeText = 30
          this.opacityText = 0.3
        } else {
          this.radius = 0
          this.widthText = 150
          this.heightText = 100
          this.fontSizeText = 20
          this.opacityText = 1
        }
      })
    Image($r('app.media.startIcon'))
      .scale({
        x: this.scaleImage,
        y: this.scaleImage
      })
      .translate({ x: this.translateImage, y: this.translateImage })
      .rotate({ angle: this.angleImage })// .transform(matrix4.identity()
        //   .translate({ x: this.translateImage, y: this.translateImage })
        //   .scale({ x: this.scaleImage, y: this.scaleImage })
        //   .rotate({
        //     angle: this.angleImage
        //   }))
      .width(110)
      .aspectRatio(1)
      .animation({
        duration: 500,
        curve: Curve.Smooth
      })
      .onClick(() => {
        if (this.scaleImage == 1) {
          this.scaleImage = 0.4
          this.translateImage = 100
          this.angleImage = 45
        } else {
          this.scaleImage = 1
          this.translateImage = 0
          this.angleImage = 0
        }
      })

  }.width('100%')
  .height('100%')
  .justifyContent(FlexAlign.Center)
}

自定义属性

@AnimatableExtend 使用这个来重写控件的属性

@AnimatableExtend(Text)
function animatableFontSize(size: number) {
  .fontSize(size) // 调用系统属性接口
}

Text("AnimatableProperty")
  .backgroundColor("#0C000000")
  .animatableFontSize(this.fontSize)// 第二步:将自定义可动画属性接口设置到组件上
  .animation({ duration: 1100, curve: "ease" })// 第三步:为自定义可动画属性接口绑定动画
  .width(250)
  .height(140)
  .textAlign(TextAlign.Center)
  .onClick(() => {
    this.fontSize = this.fontSize == 20 ? 30 : 20; // 第四步:改变自定义可动画属性的参数,产生动画
  })

转场动画

转场动画是指对将要出现或消失的组件做动画,对组件进行动画,当组件挂载的时候会,卸载的时候

挂载/卸载动画

// 第一步,创建 TransitionEffect
private effect: TransitionEffect =
  TransitionEffect.OPACITY.animation({ curve: Curve.Smooth })
    .combine(TransitionEffect.scale({ x: 0, y: 0 }))
    .combine(TransitionEffect.rotate({ angle: 90 }))
    .combine(TransitionEffect.translate({ y: 150 }))

if (this.isPresent) {
  Column() {}
  .justifyContent(FlexAlign.Center)
  .width(150)
  .height(150)
  .borderRadius(10)
  .backgroundColor(0xf56c6c)
  // 第二步:将转场效果通过transition接口设置到组件
  .transition(this.effect)
}

模态转场

  • bindContentCover 弹出全屏的模态组件。 用于自定义全屏的模态展示界面,结合转场动画和共享元素动画可实现复杂转场动画效果,如缩略图片点击后查看大图。
  • bindSheet 弹出半模态组件。 用于半模态展示界面,如分享框。
  • bindMenu 弹出菜单,点击组件后弹出。 需要Menu菜单的场景,如一般应用的“+”号键。
  • bindContextMenu 弹出菜单,长按或者右键点击后弹出。 长按浮起效果,一般结合拖拽框架使用,如桌面图标长按浮起。
  • bindPopup 弹出Popup弹框。 Popup弹框场景,如点击后对某个组件进行临时说明。
  • if

共享元素动画

页面间的

使用 geometryTransition 绑定同样的东西 和 transition 以及 属性动画配合做出来的效果,再加上id,加了id之后,新建的spring图片会复用之前的spring图片节点,不会重新创建节点,也就不会有重影问题

.geometryTransition("picture")
.transition(TransitionEffect.OPACITY)
.id('item1')
Stack({ alignContent: Alignment.Center }) {
  if (this.isShow) {
    Image('https://pic2.zhimg.com/80/v2-393c15200b287070fbb3105c08e6ebf5_1440w.webp')
      .width(200)
      .height(200)
      .borderRadius(100)
      .clip(true)
      .geometryTransition("picture")
      .transition(TransitionEffect.OPACITY)
      .id('item1')
  } else {
    // geometryTransition 此处绑定的是容器,那么容器内的子组件需设为相对布局跟随父容器变化,
    // 套多层容器为了说明相对布局约束传递
    Image('https://pic2.zhimg.com/80/v2-393c15200b287070fbb3105c08e6ebf5_1440w.webp')
      .size({ width: '100%', height: '100%' })
      .width(100)
      .height(100)
      .borderRadius(50)
      .clip(true)
      .geometryTransition("picture")// transition保证节点离场不被立即析构,设置通用转场效果
      .transition(TransitionEffect.OPACITY)
      .position({ x: 40, y: 40 })
      .id('item2')
  }
}
.onClick(() => {
  animateTo({
    curve: curves.springMotion()
  }, () => {
    this.isShow = !this.isShow;
  })
})

粒子动画