【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(十四)

news2024/11/29 12:29:37

课程地址: 黑马程序员HarmonyOS4+NEXT星河版入门到企业级实战教程,一套精通鸿蒙应用开发

(本篇笔记对应课程第 22 节)

P22《21.ArkUI-实现摇杆功能》

本节我们将小鱼动画案例中的按钮控制改为摇杆控制,用来熟悉和巩固动画效果相关的知识点。

分析实现思路:摇杆控制器包括大圆区域和里面的小圆球,通过用手指控制小圆球移动,来控制小鱼位置变化。

1、我们可以获取手指位置坐标{x,y},并计算出这个坐标值与大圆中心点坐标值的差值,即图中红色横线与竖线,用vx与vy表示。

2、有了这两个值,就可以得到手指与中心点连线与x轴正轴方向的夹角angle,如图中标识出的夹角。我们可以得到手指与中心点连线之间的距离(已知vx,vy,相当于已知直角三角形两条直角边,求斜边长度),这个距离如果超过大圆区域,就取大圆半径,因为小圆球的移动区域需要在大圆范围内,不能移动出大圆。

3、有了这个距离(图中蓝色直角三角形斜边长)和夹角angle,可以得到蓝色直角三角形的两条直角边长,也就是小圆球的移动坐标值。有了这个移动坐标值,我们就可以控制小圆球的移动了。

在这里插入图片描述

4、控制小鱼位置:小鱼移动需要有一个速度值,这个速度值相当于其在某个方向上移动出去的距离,也就是相当于黄色直角三角形的斜边长,有了斜边长和angle角度,可以得到黄色直角三角形的两条直角边长,即小鱼的移动坐标距离。

在这里插入图片描述

摇杆区静态代码:

在这里插入图片描述

给大摇杆添加touch事件:

在这里插入图片描述

事件中的逻辑思路如下几步注释:

在这里插入图片描述

screenX 与 screenY 指的是手指触摸点在整个屏幕中的坐标,而 x 与 y 指的是手指触摸点在当前容器中的坐标。我们需要的是 x 与 y
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

测试效果小圆球拖动效果,发现几个小问题:

首先,拖动小圆球拖不动,只有在大圆区域内拖动才能使小圆球移动,这是因为touch事件仅仅是加在大圆上的。

解决:将加在大圆上的 touch 事件改为加在 大圆与小圆球的外层容器上:

在这里插入图片描述

其次,小圆球的拖动不够圆滑,没有动画效果
解决:用显式动画的方式给小球增加动画效果:

在这里插入图片描述

使用curves库(需要导入)中的动画效果:

在这里插入图片描述

再次,手指松开后小球位置需要还原:这就需要对事件类型做出判断,根据不同事件分别进行处理:手指松开时还原小球位置;手指移动时处理小球跟随效果,即我们写出的1-5步的代码:

在这里插入图片描述

给手指松开小球位置还原增加动画效果:

在这里插入图片描述

到这里就完成了摇杆小球跟随手指移动的效果。

接下来我们来控制小鱼的位置:

在这里插入图片描述

在这里插入图片描述

此时测试发现效果是:只有移动小球时,小鱼位置才随之改变,移动小球停止,小鱼就不动了。效果不够圆滑生动。实现小鱼在手指控制小球过程中持续移动,这就需要开启一个定时器。

要想人眼看到动画效果,最低每秒要24帧。定时器设置为40毫秒时,每秒就是25帧。

在这里插入图片描述

在这里插入图片描述

此时发现小鱼不会随着游动方向改变角度,完善小鱼的角度:

在这里插入图片描述

在这里插入图片描述

实践:

// AnimationPage.ets
import router from '@ohos.router'
import curves from '@ohos.curves'

@Styles function btnStyle(){
  .backgroundColor('rgba(0,0,0,0.2)')
}

@Entry
@Component
struct AnimationPage {
  // 小鱼坐标
  @State fishX: number = 400
  @State fishY: number = 180
  // 小鱼角度
  @State angle: number = 0
  // 小鱼图片
  @State src:Resource = $r('app.media.fish')

  // 是否开始游戏
  @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() {
      Column() {
        Stack(){
          // 返回按钮
          Button('返回')
            .position({x:0,y:0})
            .btnStyle()
            .onClick(()=>{
              router.back()
            })

          // 开始游戏按钮
          if(!this.isBegin){
            Button('开始游戏')
              .onClick(()=>{
                animateTo(
                  {duration:1000},
                  ()=>{
                    this.isBegin = true
                  }
                )
              })
          }else{
            // 小鱼图片
            Image(this.src)
              .width('80')
              .position({x: this.fishX - 40, y: this.fishY - 40})
              .rotate({angle:this.angle, centerX:'50%', centerY:'50%'})
              // .animation({duration:500, tempo:1})
              .transition({
                type:TransitionType.Insert,
                opacity:0,
                translate:{x: -200}
              })

          }


          // 操作按钮
          /*Row(){
            Button('←')
              .btnStyle()
              .type(ButtonType.Circle)
              .onClick(()=>{
                animateTo(
                  { duration:500 },
                  ()=>{
                    this.src = $r('app.media.fish_left')
                    this.fishX -= 40
                  }
                )
              })
            Column({
              space:20
            }){
              Button('↑')
                .btnStyle()
                .type(ButtonType.Circle)
                .onClick(()=>{
                  animateTo(
                    {duration:500},
                    ()=>{
                      this.fishY -= 40
                    }
                  )
                })
              Button('↓')
                .btnStyle()
                .type(ButtonType.Circle)
                .onClick(()=>{
                  animateTo(
                    {duration:500},
                    ()=>{
                      this.fishY += 40
                    }
                  )
                })
            }
            Button('→')
              .btnStyle()
              .type(ButtonType.Circle)
              .onClick(()=>{
                animateTo(
                  { duration:500 },
                  ()=>{
                    this.src = $r('app.media.fish')
                    this.fishX += 40
                  }
                )
              })
          }
          .width(120)
          .position({x:10,y:250})
          .justifyContent(FlexAlign.Center)*/

          // 摇杆控制
          Row(){
            Circle({ width: this.maxRadius * 2, height:this.maxRadius * 2})
              .fill('#20101010')
              .position({x:this.centerX - this.maxRadius, y:this.centerX - this.maxRadius })

            Circle({ width: this.radius * 2, height:this.radius * 2})
              // .fill('#403A3A3A')
              .fill('#d3601010')
              .position({x:this.positionX - this.radius, y:this.positionY - this.radius })
          }
            .width(240)
            .height(240)
            .position({x:0, y:120})
            .onTouch(this.handleTouchEvent.bind(this))
        }
        .width('100%')
        .height('100%')
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundImage($r('app.media.fish_bg'),ImageRepeat.NoRepeat)
    .backgroundImageSize(ImageSize.Cover)
    .backgroundImagePosition(Alignment.Bottom)
  }

  handleTouchEvent = (event:TouchEvent)=>{
    switch (event.type){
      case TouchType.Up:
        // 还原小球位置
        animateTo(
          { curve:curves.springMotion() },
          ()=>{
            this.positionX = this.centerX
            this.positionY = this.centerY
          }
        )
        // 还原小鱼速度
        this.speed = 0
        // 还原小鱼角度
        this.angle = 0
        // 取消定时任务
        clearInterval(this.taskId)
        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)
      // 5、计算摇杆小球的坐标
        this.sin = Math.sin(angle)
        this.cos = Math.cos(angle)
        animateTo(
          { curve:curves.responsiveSpringMotion() },
          ()=>{
            // 修改摇杆小球的坐标
            this.positionX = this.centerX + distance * this.cos
            this.positionY = this.centerY + distance * this.sin
            // 修改小鱼的坐标
            this.speed = 5
            /*this.fishX += this.speed * this.cos
            this.fishY += this.speed * this.sin*/

            // 小鱼向右游
            if(Math.abs(angle * 2) < Math.PI){
              this.src = $r('app.media.fish')
            }else{  // 小鱼向左游
              this.src = $r('app.media.fish_left')
              angle = angle < 0 ? angle + Math.PI : angle - Math.PI  // todo 这句不太懂
            }

            // 修改小鱼的角度
            this.angle = angle * 180 / Math.PI
          }
        )
        break;
    }
  }

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1844395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面向AI时代的软件开发新范式

作为一名软件开发者&#xff0c;有幸站在了AI时代的风口浪尖。在这篇博客中&#xff0c;我将分享我的个人看法&#xff0c;一起走向AI时代软件开发新范式。 首先&#xff0c;我们要明确软件开发活动产生的各种制品&#xff0c;都是人类知识的载体&#xff0c;也是人类文明的高级…

校园疫情防控健康打卡系统

摘 要 自疫情出现以来&#xff0c;全世界人民的生命安全和健康都面临着严重威胁。高校是我国培养人才的重要基地&#xff0c;其安全和稳定影响着社会的发展和进步。因此&#xff0c;各高校高度重视疫情防控工作&#xff0c;并在校园疫情防控中引入了健康打卡系统。本论文主要研…

Cookie-SameSite属性 前端请求不带cookie的问题解决方案

最近遇到了前端请求后端不带cookie的问题&#xff0c; 请求时header里面就是没有cookie 查看响应应该是这个问题 SameSite是一个cookie属性&#xff0c;用于控制浏览器是否在跨站点请求中发送cookie。它有三个可能的值&#xff1a; 1. Strict&#xff08;严格模式&#xff09…

如何使用pwclient从社区邮件列表获取相关补丁

最近在调试Qualcomm的QCA2066 WiFi 6E平台&#xff0c;主控处理器信息如下所示&#xff1a; 6nm AMD APU CPU&#xff1a;Zen 2 4c/8t、2.4-3.5GHz&#xff08;最高可达 448GFlops FP32&#xff09; GPU&#xff1a;8 RDNA 2 CUs、1.6GHz&#xff08;1.6 TFlops FP32&#xff0…

Tomcat配置详解

文章目录 一、配置文件介绍配置文件日志文件 二、组件组件分层和分类核心组件Tomcat处理请求过程URL对应关系 三、部署java程序手动部署搭建博客状态页 四、常见配置详解tomcat端口号安全配置管理虚拟主机配置Context配置 四、Tomcat Nginx动静分离 一、配置文件介绍 配置好环…

代码讲解——ssm+jsp+maven项目目录结构说明

1 applicationContext.xml 应用上下文配置 2 db.properties 数据库配置 3 log4j.properties日志配置 4 mybatis-config.xml mybatis配置 5 springmvc.xml springmvc配置

【ai】tx2-nx:安装深度学习环境及4.6对应pytorch

参考:https://www.waveshare.net/wiki/Jetson_TX2_NX#AI.E5.85.A5.E9.97.A8 英伟达2021年发布的的tritionserver 2.17 版本中,backend 有tensorflow1 和 onnxruntime ,他们都是做什么用的,作为backend 对于 triton 推理server意义是什么,是否应该有pytorch? Triton Infer…

新版二开微信发卡小程序源码卡密系统/支持流量主

新版二开微信发卡小程序源码卡密系统支持流量主。裂变扩展多种领取模式二次开发的发卡小程序源码&#xff0c;其后台采用PHP编写&#xff0c;支持用户通过付费购卡或者观看视频广告领取卡密。 该小程序还支持流量主&#xff0c;因为功能需要&#xff0c;就进行了二开&#xff…

LeetCode 热题100 --哈希

哈希 哈希&#xff0c;有限空间映射一个无限的空间。在空间内&#xff0c;有序化进行快速查询。 用空间换时间。 1.两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组…

如何使用ChatGPT辅助设计工作

文章目录 设计师如何使用ChatGPT提升工作效率&#xff1f;25个案例告诉你&#xff01;什么是 prompt&#xff1f;咨询信息型 prompt vs 执行任务 prompt编写出色 prompt 的基本思路撰写 prompt 的案例和技巧1、将 ChatGPT 视作专业人士2、使用 ChatGPT 创建表单3、使用 ChatGPT…

论文学习 Learning Robust Representations via Multi-View Information Bottleneck

Code available at https://github.com/mfederici/Multi-View-Information-Bottleneck 摘要&#xff1a;信息瓶颈原理为表示学习提供了一种信息论方法&#xff0c;通过训练编码器保留与预测标签相关的所有信息&#xff0c;同时最小化表示中其他多余信息的数量。然而&#xff0…

驶向未来,智慧加油新体验——我们的加油App开发之旅

一、引言 在数字化与智能化交织的时代&#xff0c;每一次出行都呼唤着更加高效、便捷的服务。为了满足广大车主对加油服务的更高需求&#xff0c;我们倾力打造了一款创新的加油App&#xff0c;旨在为您的驾驶生活带来前所未有的智慧新体验。 二、洞察需求&#xff0c;创新服务…

torch.optim 之 Algorithms (Implementation: for-loop, foreach, fused)

torch.optim的官方文档 官方文档中文版 一、Implementation torch.optim的官方文档在介绍一些optimizer Algorithms时提及它们的implementation共有如下三个类别&#xff1a;for-loop, foreach (multi-tensor), and fused。 Chat-GPT对这三个implementation的解释是&#xf…

光伏设计需要设计哪些方面?

光伏设计是一项复杂而关键的工作&#xff0c;它涉及到多个方面的综合考虑&#xff0c;以确保光伏系统的效率、安全性和可持续性。下面将详细探讨光伏设计需要设计的几个方面。 一、系统规模与布局 光伏设计的首要任务是确定系统的规模和布局。这包括评估安装地点的光照资源、可…

工业智能网关如何与设备连接?天拓四方

随着工业4.0时代的来临&#xff0c;智能化、自动化已成为工业生产的标配。在这样的背景下&#xff0c;工业智能网关应运而生&#xff0c;成为连接工业设备、实现数据交互与管理的关键节点。本文将阐述工业智能网关如何与设备连接&#xff0c;旨在为读者提供一套清晰、实用的解决…

实现Hexo新建博文时自带随机默认封面

文章目录 1. Hexo模版2. 准备封面和缩略图3. 新建博文脚本windowsLinux 4. 效果展示 前提是选择的主题在Front-matter中支持cover和thumbnail&#xff0c;主题之间对于这两个属性的定义可能并不用&#xff0c;如果不适用&#xff0c;只需要根据逻辑修改脚本即可。 1. Hexo模版…

python爬虫之selenium自动化操作

python爬虫之selenium自动化操作 需求&#xff1a;操作淘宝去掉弹窗广告搜索物品后进入百度回退又前进 selenium模块的基本使用 问题&#xff1a;selenium模块和爬虫之间具有怎样的关联? 1、便捷的获取网站中动态加载的数据 2、便捷实现模拟登录 什么是selenium模块&#x…

视频去水印,视频去水印软件

有时候我们在网上下载了一些喜欢的视频&#xff0c;但是却发现上面有水印&#xff0c;影响观看体验。今天我就来教大家一个轻松去除视频水印的简单的方法。 一、使用专业视频编辑软件去水印 市面上有很多专业的视频编辑软件&#xff0c;如Adobe Premiere Pro&#xff0c;它们都…

通过python代码将html文件另存为xlsx文件

通过python实现办公流程自动化&#xff0c;经常遇到从网页上下载的excel文件为html格式的表格&#xff08;或者后缀为xls/xlsx&#xff0c;实际依旧为html格式&#xff09;&#xff0c;无法通过python处理文件数据&#xff0c;比如合并excel文件&#xff0c;此时就需要将文件另…

Element-ui中Table表格无法显示

Element-ui中Table表格无法显示 在使用过程中发现样式正常显示但是table就是不显示&#xff0c;研究了一段时间后&#xff0c;发现问题是项目结构的问题 当你创建vue和安装el的时候&#xff0c;一定要注意进入到正确的项目文件夹&#xff0c;如果在外面也出现一个package.jso…