HarmonyOS4-ArkUI组件动画

本文介绍了如何在ArkUI组件中实现动画效果,包括组件属性动画(如小鱼游动)、显示动画(配合`animateTo`)和摇杆功能(基于触摸事件和三角函数)。作者详细展示了上下左右箭头控制小鱼移动的示例以及如何结合转场动画进行游戏界面的过渡。
摘要由CSDN通过智能技术生成

一、ArkUI组件属性动画和显示动画

显示动画:

案例:上下左右箭头控制小鱼的游动  具体代码如下:

import router from '@ohos.router'

@Entry
@Component
struct AnimationPage {
  // 小鱼坐标
  @State fishX: number = 200
  @State fishY: number = 180
  // 小鱼角度
  @State angle: number = 0
  // 小鱼图片
  @State src: Resource = $r('app.media.fish')
  // 是否开始游戏
  @State isBegin: boolean = false

  build() {
    Row() {
      Stack() {
        // 返回按钮
        Button('返回')
          .position({ x: 0, y: 0 })
          .backgroundColor('#20101010')
          .onClick(() => {
            // 返回上一页
            router.back()
          })
        if (!this.isBegin) {
          // 开始游戏
          Button('开始游戏')
            .onClick(() => {
              // 点击后显示小鱼
              this.isBegin = true
            })
        } else {
          // 小鱼图片
          Image(this.src)
            .position({ x: this.fishX - 20, y: this.fishY - 20 }) // 中心点坐标
            .rotate({ angle: this.angle, centerX: '50%', centerY: '50%' })
            .width(40)
            .height(40)
          //.animation({duration: 500})

          // 操作按钮
          Row() {
            Button('⬅').backgroundColor('#20101010')
              .onClick(() => {
                // this.fishX -= 20
                // this.src = $r('app.media.fish_rev')
                // 显示动画
                animateTo({
                  duration: 500
                },
                  () => {
                    this.fishX -= 20
                    this.src = $r('app.media.fish_rev')
                  })
              })
            Column({ space: 40 }) {
              Button('⬆').backgroundColor('#20101010')
                .onClick(() => {
                  this.fishY -= 20
                })
              Button('⬇').backgroundColor('#20101010')
                .onClick(() => {
                  this.fishY += 20
                })
            }

            Button('➡').backgroundColor('#20101010')
              .onClick(() => {
                this.fishX += 20
                this.src = $r('app.media.fish')
              })
          }
          .width(240)
          .height(240)
        }
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
  }
}

二、ArkUI组件转场动画

代码如下:

import router from '@ohos.router'

@Entry
@Component
struct AnimationPage {
  // 小鱼坐标
  @State fishX: number = 200
  @State fishY: number = 180
  // 小鱼角度
  @State angle: number = 0
  // 小鱼图片
  @State src: Resource = $r('app.media.fish')
  // 是否开始游戏
  @State isBegin: boolean = false

  build() {
    Row() {
      Stack() {
        // 返回按钮
        Button('返回')
          .position({ x: 0, y: 0 })
          .backgroundColor('#20101010')
          .onClick(() => {
            // 返回上一页
            router.back()
          })
        if (!this.isBegin) {
          // 开始游戏
          Button('开始游戏')
            .onClick(() => {
              // 点击后显示小鱼
              // this.isBegin = true

              // 转场动画需结合animateTo才能生效
              animateTo({
                duration: 1000
              },
                () => {
                  // 点击后显示小鱼
                  this.isBegin = true
                })
            })
        } else {
          // 小鱼图片
          Image(this.src)
            .position({ x: this.fishX - 20, y: this.fishY - 20 }) // 中心点坐标
            .rotate({ angle: this.angle, centerX: '50%', centerY: '50%' })
            .width(40)
            .height(40)
              //.animation({duration: 500})
              // 添加转场动画
            .transition({
              // 开始游戏,入场动画
              type: TransitionType.Insert,
              opacity: 0, //一开始是透明的
              translate: { x: -250 }
            })
        }
        // 操作按钮
        Row() {
          Button('⬅').backgroundColor('#20101010')
            .onClick(() => {
              // this.fishX -= 20
              // this.src = $r('app.media.fish_rev')
              // 显示动画
              animateTo({
                duration: 500
              },
                () => {
                  this.fishX -= 20
                  this.src = $r('app.media.fish_rev')
                })
            })
          Column({ space: 40 }) {
            Button('⬆').backgroundColor('#20101010')
              .onClick(() => {
                this.fishY -= 20
              })
            Button('⬇').backgroundColor('#20101010')
              .onClick(() => {
                this.fishY += 20
              })
          }

          Button('➡').backgroundColor('#20101010')
            .onClick(() => {
              this.fishX += 20
              this.src = $r('app.media.fish')
            })
        }
        .width(240)
        .height(240)
        .justifyContent(FlexAlign.Center)
        .position({x: 0, y: 120})
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
  }
}

三、ArkUI组件实现摇杆功能

此功能自行开发

此块涉及到的主要是算法 ,比如三角函数

角度正弦和余弦

import router from '@ohos.router'
import { TouchEvent } from '@ohos.multimodalInput.touchEvent'
import curves from '@ohos.curves'

@Entry
@Component
struct AnimationPage {
  // 小鱼坐标
  @State fishX: number = 200
  @State fishY: number = 180
  // 小鱼角度
  @State angle: number = 0
  // 小鱼图片
  @State src: Resource = $r('app.media.fish')
  @State srcBg: Resource = $r('app.media.bg')
  // 是否开始游戏
  @State isBegin: boolean = false

  // 摇杆中心区域坐标
  private centerX: number = 120
  private centerY: number = 120

  // 大、小圆半径
  private maxRadius: number = 100
  private radius: number = 20

  // 摇杆小圆球初始位置
  @State positionX: number = this.centerX;
  @State positionY: number = this.centerY;

  // 角度正弦和余弦
  sin: number = 0
  cos: number = 0

  // 小鱼移动速度
  speed: number = 0

  // 任务id
  taskId: number = -1

  build() {
    Row() {
      Stack() {
        // 返回按钮
        Button('返回')
          .position({ x: 0, y: 0 })
          .backgroundColor('#20101010')
          .onClick(() => {
            // 返回上一页
            router.back()
          })
        if (!this.isBegin) {
          // 开始游戏
          Button('开始游戏')
            .onClick(() => {
              // 点击后显示小鱼
              // this.isBegin = true

              // 转场动画需结合animateTo才能生效
              animateTo({
                duration: 1000
              },
                () => {
                  // 点击后显示小鱼
                  this.isBegin = true
                })
            })
        } else {
          // 小鱼图片
          Image(this.src)
            .position({ x: this.fishX - 20, y: this.fishY - 20 }) // 中心点坐标
            .rotate({ angle: this.angle, centerX: '50%', centerY: '50%' })
            .width(40)
            .height(40)
              //.animation({duration: 500})
              // 添加转场动画
            .transition({
              // 开始游戏,入场动画
              type: TransitionType.Insert,
              opacity: 0, //一开始是透明的
              translate: { x: -250 }
            })
        }
        // 操作按钮
        Row() {
          Circle( {width: this.maxRadius * 2, height: this.maxRadius * 2})
            .fill('#20101010')
            .position({x: this.centerX - this.maxRadius, y: this.centerY - this.maxRadius})

          Circle( {width: this.radius * 2, height: this.radius * 2})
            .fill('#403A3A3A')
            .position({x: this.positionX - this.radius, y: this.positionY - this.radius})
        }
        .width(240)
        .height(240)
        .justifyContent(FlexAlign.Center)
        .position({x: 0, y: 120})
        .onTouch(this.handleTouchEvent.bind(this))
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
    .width('100%')
    .backgroundImage(this.srcBg)
  }

  // 处理手指移动的函数
  handleTouchEvent(event: TouchEvent) {
    // 1、先获取手指位置坐标
    // .x .y 我获取不到? 为啥
    let x = event.touches[0].screenX
    // @ts-ignore
    let y = event.touches[0].screenY
    // 2、计算手指与中心点的坐标差值
    let vx = x - this.centerX
    let vy = y - this.centerY
    // 3、计算手指与中心点连线和x轴正半轴的夹角,单位是弧度
    let angle = Math.atan2(vy, vx);
    // 4、计算手指与中心点的距离(角度正弦和余弦)
    let distance = this.getDistance(vx, vy)
    // 5、计算摇杆小球的坐标(x轴和y轴)
    this.sin = Math.sin(angle)
    this.cos = Math.cos(angle)
    animateTo({curve: curves.responsiveSpringMotion()},
      () => {
        this.positionX = this.centerX + (distance * this.sin)
        this.positionY = this.centerY + (distance * this.cos)
      })
  }

  getDistance(x: number, y: number) {
    let d = Math.sqrt(x * x + y * y)
    return Math.min(d, this.maxRadius)
  }
}

最终版:

import router from '@ohos.router'
import curves from '@ohos.curves'

@Entry
@Component
struct AnimationPage {
  // 小鱼坐标
  @State fishX: number = 200
  @State fishY: number = 180
  // 小鱼角度
  @State angle: number = 0
  // 小鱼图片
  @State src: Resource = $r('app.media.fish')
  @State srcBg: Resource = $r('app.media.bg')
  // 是否开始游戏
  @State isBegin: boolean = false

  // 摇杆中心区域坐标
  private centerX: number = 120
  private centerY: number = 120

  // 大、小圆半径
  private maxRadius: number = 100
  private radius: number = 20

  // 摇杆小圆球初始位置
  @State positionX: number = this.centerX;
  @State positionY: number = this.centerY;

  // 角度正弦和余弦
  sin: number = 0
  cos: number = 0

  // 小鱼移动速度
  speed: number = 0

  // 任务id
  taskId: number = -1

  build() {
    Row() {
      Stack() {
        // 返回按钮
        Button('返回')
          .position({ x: 0, y: 0 })
          .backgroundColor('#20101010')
          .onClick(() => {
            // 返回上一页
            router.back()
          })
        if (!this.isBegin) {
          // 开始游戏
          Button('开始游戏')
            .onClick(() => {
              // 点击后显示小鱼
              // this.isBegin = true

              // 转场动画需结合animateTo才能生效
              animateTo({
                duration: 1000
              },
                () => {
                  // 点击后显示小鱼
                  this.isBegin = true
                })
            })
        } else {
          // 小鱼图片
          Image(this.src)
            .position({ x: this.fishX - 20, y: this.fishY - 20 }) // 中心点坐标
            .rotate({ angle: this.angle, centerX: '50%', centerY: '50%' })
            .width(40)
            .height(40)
              //.animation({duration: 500})
              // 添加转场动画
            .transition({
              // 开始游戏,入场动画
              type: TransitionType.Insert,
              opacity: 0, //一开始是透明的
              translate: { x: -250 }
            })
        }
        // 操作按钮
        Row() {
          Circle( {width: this.maxRadius * 2, height: this.maxRadius * 2})
            .fill('#20101010')
            .position({x: this.centerX - this.maxRadius, y: this.centerY - this.maxRadius})

          Circle( {width: this.radius * 2, height: this.radius * 2})
            .fill('#403A3A3A')
            .position({x: this.positionX - this.radius, y: this.positionY - this.radius})
        }
        .width(240)
        .height(240)
        .justifyContent(FlexAlign.Center)
        .position({x: 0, y: 120})
        .onTouch(this.handleTouchEvent.bind(this))
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
    .width('100%')
    .backgroundImage(this.srcBg)
  }

  // 处理手指移动的函数
  handleTouchEvent(event: TouchEvent) {
    switch (event.type) {
      case TouchType.Up:
        // 还原小鱼的速度
        this.speed = 0
        // 取消定时任务
        clearInterval(this.taskId)
        // 还原摇杆小球的坐标 springMotion:还原动画
        animateTo({curve: curves.springMotion()},
          () => {
            this.positionX = this.centerX
            this.positionY = this.centerY
            this.angle = 0
          })
        break
      case TouchType.Down:
        // 开始定时任务
        this.taskId = setInterval(() => {
          this.fishX += this.speed * this.cos
          this.fishY += this.speed * this.sin
        }, 40);
        break
      case TouchType.Move:
        // 1、先获取手指位置坐标
        let x = event.touches[0].x
        let y = event.touches[0].y
        // 2、计算手指与中心点的坐标差值
        let vx = x - this.centerX
        let vy = y - this.centerY
        // 3、计算手指与中心点连线和x轴正半轴的夹角,单位是弧度
        let angle = Math.atan2(vy, vx);
        // 4、计算手指与中心点的距离(角度正弦和余弦)
        let distance = this.getDistance(vx, vy)
        this.sin = Math.sin(angle)
        this.cos = Math.cos(angle)
        // responsiveSpringMotion:跟手动画
        animateTo({curve: curves.responsiveSpringMotion()},
          () => {
            // 5、计算摇杆小球的坐标(x轴和y轴) 使用显示动画改变坐标
            this.positionX = this.centerX + (distance * this.sin)
            this.positionY = this.centerY + (distance * this.cos)

            // 6、修改小鱼的角度  [弧度转角度]
            if (Math.abs(angle * 2) < Math.PI) {
              // 判断弧度是否小于90度  正负90度 朝右游
              this.src = $r('app.media.fish')
            } else {
              this.src = $r('app.media.fish_rev')
              angle = angle < 0 ? angle + Math.PI : angle - Math.PI
            }
            this.angle = angle * 180 / Math.PI
            this.speed = 5
          })
        break
    }
  }

  getDistance(x: number, y: number) {
    let d = Math.sqrt(x * x + y * y)
    return Math.min(d, this.maxRadius)
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值