【如此之白】ETS简单实现AnimateCSS动画 原创 精华

如此之白
发布于 2022-4-20 15:13
浏览
11收藏

显式动画

接口名称 功能描述
animateTo(value: AnimationOption, event: ()=> void) : void 提供全局animateTo显式动画接口来指定由于闭包代码导致的状态变化插入过渡动效。 event指定显示动效的闭包函数,在闭包函数中导致的状态变化系统会自动插入过渡动画。

参考文档
https://gitee.com/openharmony/docs/blob/5654c2b940ab3e2f4f0baf435e630c4ef3536428/zh-cn/application-dev/reference/arkui-ts/ts-explicit-animation.md

来看一个简单的示例
【如此之白】ETS简单实现AnimateCSS动画-鸿蒙开发者社区

@Entry
@Component
struct AnimationPage {
  // 位移属性
  @State _translate: TranslateOptions = {
    x: 0,
    y: 0,
    z: 0
  }

  build() {
    Flex({
      alignItems: ItemAlign.Center,
      justifyContent: FlexAlign.Center,
      direction: FlexDirection.Column
    }) {
      Button('执行动画').margin({ bottom: 50 }).onClick(() => {
        //添加一个简单显式动画
        animateTo({
          duration: 1000, // 动画时长
          tempo: 0.5, // 播放速率
          curve: Curve.EaseInOut, // 动画曲线
          delay: 0, // 动画延迟
          iterations: 1, // 播放次数
          playMode: PlayMode.Normal, // 动画模式
        }, () => {
          //闭包内更改状态
          this._translate = {
            x: 0,
            y: 100,
            z: 0
          }
        })
      })

      Column() {
        Text('Animate.css')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .fontColor('#351c75')
          .translate(this._translate) // 位移变换
      }
    }
    .width('100%')
    .height('100%')
  }
}

如果我们希望向下位移完成后,再向右位移,就需要在第一个动画完成后再进行第二个动画,即在第一个动画的onFinish函数中执行第二个动画。

这样组合起来可以构成一个更复杂的连续动画。

【如此之白】ETS简单实现AnimateCSS动画-鸿蒙开发者社区

// 单步动画执行函数
animationStep(value: AnimateParam, event: () => void) {
    return () => {
      return new Promise((resolve) => {
        let onFinish = value.onFinish
        value.onFinish = () => {
          if(onFinish) onFinish()
          resolve(true)
        }
        animateTo(value, event)
      })
    }
}

创建4步动画

aboutToAppear() {
    // 每步动画执行时长
    let time = 200
    this.step1 = this.animationStep({
      duration: time, // 动画时长
      tempo: 0.5, // 播放速率
      curve: Curve.EaseInOut, // 动画曲线
      delay: 0, // 动画延迟
      iterations: 1, // 播放次数
      playMode: PlayMode.Normal, // 动画模式
      onFinish: () => {
        // 动画执行完成
        console.info('play end')
      }
    }, () => {
      //闭包内更改状态
      this._translate = {
        x: 0,
        y: 100,
        z: 0
      }
    })


    this.step2 = this.animationStep({
      duration: time, // 动画时长
      tempo: 0.5, // 播放速率
      curve: Curve.EaseInOut, // 动画曲线
      delay: 0, // 动画延迟
      iterations: 1, // 播放次数
      playMode: PlayMode.Normal, // 动画模式
      onFinish: () => {
        // 动画执行完成
        console.info('play end')
      }
    }, () => {
      //闭包内更改状态
      this._translate = {
        x: 100,
        y: 100,
        z: 0
      }
    })

    this.step3 = this.animationStep({
      duration: time, // 动画时长
      tempo: 0.5, // 播放速率
      curve: Curve.EaseInOut, // 动画曲线
      delay: 0, // 动画延迟
      iterations: 1, // 播放次数
      playMode: PlayMode.Normal, // 动画模式
      onFinish: () => {
        // 动画执行完成
        console.info('play end')
      }
    }, () => {
      //闭包内更改状态
      this._translate = {
        x: 100,
        y: 0,
        z: 0
      }
    })

    this.step4 = this.animationStep({
      duration: time, // 动画时长
      tempo: 0.5, // 播放速率
      curve: Curve.EaseInOut, // 动画曲线
      delay: 0, // 动画延迟
      iterations: 1, // 播放次数
      playMode: PlayMode.Normal, // 动画模式
      onFinish: () => {
        // 动画执行完成
        console.info('play end')
      }
    }, () => {
      //闭包内更改状态
      this._translate = {
        x: 0,
        y: 0,
        z: 0
      }
    })
}

顺序执行4步动画

Button('执行动画').margin({ bottom: 50 }).onClick(async () => {
    await this.step1()
    await this.step2()
    await this.step3()
    await this.step4()
})

实现AnimateCSS动画

AnimateCSS

https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.css

https://animate.style/

pulse动画
【如此之白】ETS简单实现AnimateCSS动画-鸿蒙开发者社区

看下pulse动画样式代码

.animate__pulse {
  -webkit-animation-name: pulse;
  animation-name: pulse;
  -webkit-animation-timing-function: ease-in-out;
  animation-timing-function: ease-in-out;
}

@keyframes pulse {
  from {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }

  50% {
    -webkit-transform: scale3d(1.05, 1.05, 1.05);
    transform: scale3d(1.05, 1.05, 1.05);
  }

  to {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}

ETS实现

@State _scale: ScaleOptions = {
    x: 1,
    y: 1,
    z: 1
}

...

Column() {
    Text('Animate.css')
      .fontSize(50)
      .fontWeight(FontWeight.Bold)
      .fontColor('#351c75')
      .translate(this._translate) // 位移变换
      .scale(this._scale) //比例变化
}

动画方法

传递一个动画总时长time

第一步动画执行段为 0%-50%,所以动画执行时长为总时长time * 50%

第二步动画执行段为 50%-100%,所以动画执行时长为总时长time * 50%

async pulse(time) {
    // 0% - 50%
    let step1 = this.animationStep({
      duration: time * 0.5, // 动画时长
      tempo: 0.5, // 播放速率
      curve: Curve.EaseInOut, // 动画曲线
      delay: 0, // 动画延迟
      iterations: 1, // 播放次数
      playMode: PlayMode.Normal, // 动画模式
    }, () => {
      this._scale = {
        x: 1.05,
        y: 1.05,
        z: 1.05
      }
    })

    // 50% - 100%
    let step2 = this.animationStep({
      duration: time * 0.5, // 动画时长
      tempo: 0.5, // 播放速率
      curve: Curve.EaseInOut, // 动画曲线
      delay: 0, // 动画延迟
      iterations: 1, // 播放次数
      playMode: PlayMode.Normal, // 动画模式
    }, () => {
      this._scale = {
        x: 1,
        y: 1,
        z: 1
      }
    })

    await step1()
    await step2()
}

执行动画

Button('执行PULSE动画').margin({ bottom: 50 }).onClick(() => {
	this.pulse(500)
})

【如此之白】ETS简单实现AnimateCSS动画-鸿蒙开发者社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-9-7 11:46:24修改
14
收藏 11
回复
举报
4条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

各种动画的讲解和演示太赞了!

3
回复
2022-4-20 16:13:45
民之码农
民之码农

666

2
回复
2022-4-24 09:44:04
小昕大魔王
小昕大魔王

// 单步动画执行函数
animationStep(value: AnimateParam, event: () => void) {
    return () => {
      return new Promise((resolve) => {
        let onFinish = value.onFinish
        value.onFinish = () => {
          if(onFinish) onFinish()
          resolve(true)
        }
        animateTo(value, event)
      })
    }
}

大佬,这个单步执行动画的方法,看的不是太懂,可否详细说明下?

2
回复
2022-4-25 18:23:59
如此之白
如此之白 回复了 小昕大魔王
// 单步动画执行函数animationStep(value: AnimateParam, event: () => void) { return () => { return new Promise((resolve) => { let onFinish = value.onFinish value.onFinish = () => { if(onFinish) onFinish() resolve(true) } animateTo(value, event) }) }} 大佬,这个单步执行动画的方法,看的不是太懂,可否详细说明下?

这个等同于

// 单步动画执行函数
animationStep(value: AnimateParam, event: () => void) {
    return new Promise((resolve) => {
      // 重新实现一个onFinish方法
      let onFinish = value.onFinish
      value.onFinish = () => {
        if (onFinish) onFinish()
        // 执行onFinish方法,才将这个异步Promise对象标记为已完成
        resolve(true)
      }
      animateTo(value, event)
    })
}

// step方法
step1() {
    return this.animationStep({
      duration: 500, // 动画时长
      tempo: 0.5, // 播放速率
      curve: Curve.EaseInOut, // 动画曲线
      delay: 0, // 动画延迟
      iterations: 1, // 播放次数
      playMode: PlayMode.Normal, // 动画模式
      onFinish: () => {
        // 动画执行完成
        console.info('play end 1')
      }
    }, () => {
      //闭包内更改状态
      this._translate = {
        x: 0,
        y: 100,
        z: 0
      }
    })
  }

await 修饰的如果是Promise对象,当发现Promise被标记成已完成(resolve)或者已失败(reject)就会继续向下执行。

这样只有在await step1()执行完成onFinish后,才会继续执行await step2()

就省去了在onFinish回调中无限嵌套。我们只要顺序去执行await step()方法就可以了。

已于2022-4-26 09:33:59修改
3
回复
2022-4-26 09:26:59
回复
    相关推荐