鸿蒙应用开发学习:改进小鱼动画实现按键一直按下时控制小鱼移动和限制小鱼移出屏幕

一、前言

近期我在学习鸿蒙应用开发,跟着B站UP主黑马程序员的视频教程做了一个小鱼动画应用,UP主提供的小鱼动画源代码仅仅实现了移动组件的功能,还存在一些问题,如默认进入页面是竖屏而页面适合横屏显示;真机测试发现手机的状态栏影响到了返回键对按键事件的响应;方向键不能响应一直按着的操作;还有小鱼会移出屏幕范围。

之前已经解决了强制横屏和隐藏手机状态栏,这次则是通过一番研究,实现了按键一直按下时控制小鱼移动和限制小鱼移出屏幕这两个功能。

二、实现方法

1. 一直按下方向键时控制小鱼移动

实现这一功能是在方向键下添加onTouch方法,对按键一直按下事件进行响应。在onTouch方法中还需要判断TouchType.Down事件和TouchType.Up事件。在TouchType.Down事件时,添加animateTo方法,实现按键时一直控制小鱼移动(需要通过setInterval方法设置定时任务让animateTo方法定期执行)。在TouchType.Up事件时,通过clearInterval清除定时任务,小鱼就不会一直移动了。以向右按键为例,改造后的代码如下:

Button('→').backgroundColor('#20101010')
            .onClick(() => {              
                animateTo(
                 { duration: 500 },
                 () => {
                   this.src = $r('app.media.fish')
                   this.fishX += this.speed
                 }
               )
            })
            .onTouch((event: TouchEvent) => {
              if (event.type === TouchType.Down) {
                this.taskId = setInterval(() => {
                  animateTo(
                    { duration: 500 },
                    () => {                      
                    this.src = $r('app.media.fish')
                    this.fishX += this.speed
                    }
                  )
                }, 200)
              }
              if (event.type === TouchType.Up) {
                clearInterval(this.taskId)
                this.taskId = -1
              }
            })

        }
        .height(240)
        .width(240)
        .justifyContent(FlexAlign.Center)
        .position({ x: 0, y: 120 })

2.限制小鱼移出屏幕

实现了上面的代码后,一直按下方向键,小鱼终于可以一直移动了,但往一个方向一直移动就会移出屏幕,为让小鱼不移出屏幕,还需要对按键操作事件进行判断,检查当前小鱼的位置,只有小鱼在限制的范围内才能执行animateTo方法移动小鱼。

按下向左方向键:对小鱼的X坐标(this.fishX)进行判断。屏幕左侧边界的X值为0,小鱼的大小为40(this.fishSize)。this.fishX是小鱼图片中心点的坐标,则当小鱼接触到屏幕左侧边界时,小鱼的中心点X坐标值为20。本软件中设置的小鱼的移动速度为20(this.speed),因此,我设置的判断条件是当this.fishX >= this.fishSize时,才能执行animateTo方法。当this.fishX == 40时,再移动一次this.fishX就变成了20,此时小鱼图片的左侧边缘正好接触到屏幕左边界。

按下向上方向键:对小鱼的Y坐标(this.fishY)进行判断。屏幕上边界Y值为0,小鱼大小为40。原理和按下向左方向机一样。我设置的判断条件是当this.fishY >= this.fishSize时,才能执行animateTo方法。

对于屏幕下方的边界和屏幕右侧的边界判断需要导入模块 import display from '@ohos.display' ,并在页面的onPageShow方法获取屏幕的尺寸信息。

onPageShow() {
    // 获取旋转的方向,具体可以查看对应文档
    let orientation = window.Orientation.LANDSCAPE;

    // 获取屏幕尺寸信息
    let promise = display.getAllDisplays()
    promise.then((data) => {
      console.info('设备屏幕信息:' + JSON.stringify(data));
      console.info('testTag', '屏幕宽度px:' + JSON.stringify(data[0].width));
      console.info('testTag', '屏幕高度px:' + JSON.stringify(data[0].height));
      this.screenWidth = px2vp(data[0].width)
      this.screenHeight = px2vp(data[0].height)
      console.info('testTag', '屏幕宽度vp:' + JSON.stringify(this.screenWidth));
      console.info('testTag', '屏幕高度vp:' + JSON.stringify(this.screenHeight));
    }).catch((err) => {
      console.error('错误信息:' + JSON.stringify(err));
    })
  }

按下向右方向机:对小鱼的X坐标(this.fishX)进行判断。屏幕右侧边界的X值为变量this.screenHeight, 则判定语句为 this.fishX <= this.screenHeight - this.fishSize 。只有符合该条件是才执行animateTo方法。

按下向下方向机:对小鱼的Y坐标(this.fishY)进行判断。屏幕右侧边界的Y值为变量this.screenWidth, 则判定语句为 this.fishY <= this.screenWidth - this.fishSize 。只有符合该条件是才执行animateTo方法。

这些判断语句都要添加到方向键的onClick方法和onTouch方法。

三、完整源代码

最后上这个文件的完整源代码:

import router from '@ohos.router';
import window from '@ohos.window'; // 用于强制设为横屏
import display from '@ohos.display'

@Entry
@Component
struct Aquarium1Page {
  onPageShow() {
    // 获取旋转的方向,具体可以查看对应文档
    let orientation = window.Orientation.LANDSCAPE;
    try {
      // 设置屏幕旋转
      globalThis.windowClass.setPreferredOrientation(orientation, (err) => {
        console.log('testTag', `onPageShow函数中setPreferredOrientation方法错误码为${err}`)
      });
    } catch (exception) {
      console.error('设置失败: ' + JSON.stringify(exception));
    }
    // 获取屏幕尺寸信息
    let promise = display.getAllDisplays()
    promise.then((data) => {
      console.info('设备屏幕信息:' + JSON.stringify(data));
      console.info('testTag', '屏幕宽度px:' + JSON.stringify(data[0].width));
      console.info('testTag', '屏幕高度px:' + JSON.stringify(data[0].height));
      this.screenWidth = px2vp(data[0].width)
      this.screenHeight = px2vp(data[0].height)
      console.info('testTag', '屏幕宽度vp:' + JSON.stringify(this.screenWidth));
      console.info('testTag', '屏幕高度vp:' + JSON.stringify(this.screenHeight));
    }).catch((err) => {
      console.error('错误信息:' + JSON.stringify(err));
    })
  }

  onPageHide() {
    // 获取旋转的方向,具体可以查看对应文档
    let orientation = window.Orientation.PORTRAIT;
    try {
      // 设置屏幕旋转
      globalThis.windowClass.setPreferredOrientation(orientation, (err) => {
        console.log('testTag', `onPageHide函数中setPreferredOrientation方法错误码为${err}`)
      });
    } catch (exception) {
      console.error('设置失败: ' + JSON.stringify(exception));
    }
  }

  // 小鱼的位置
  @State fishX: number = 200
  @State fishY: number = 180
  // 小鱼的大小
  fishSize: number = 40
  // 小鱼角度
  @State angle: number = 0
  // 小鱼图片
  @State src: Resource = $r('app.media.fish')
  // 是否开始游戏
  @State isBegin: boolean = false
  // 小鱼的速度
  speed: number = 20
  // 用于控制Interval的id
  taskId: number = -1
  // 屏幕尺寸
  screenWidth: number = px2vp(2000)
  screenHeight: number = px2vp(1080)

  build() {
    Row() {
      Stack() {
        Button('返回')
          .position({ x: 20, y: 20 })
          .backgroundColor('#20101010')
          .onClick(() => {
            router.back()
          })

        if (!this.isBegin) {
          Button('开始游戏')
            .onClick(() => {
              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(this.fishSize)
            .height(this.fishSize)
              //.animation({duration: 500, curve: Curve.Smooth})
            .transition({
              type: TransitionType.Insert,
              opacity: 0,
              translate: { x: -250 }
            })
        }
        // 操作按钮
        Row() {
          // 向左移动,小鱼身体不能超出屏幕范围
          Button('←').backgroundColor('#20101010')
            .onClick(() => {
              if (this.fishX >= this.fishSize) {
                animateTo(
                  { duration: 500 },
                  () => {
                    this.src = $r('app.media.fish_rev')
                    this.fishX -= this.speed
                  }
                )
              }
            })
            .onTouch((event: TouchEvent) => {
              if (event.type === TouchType.Down) {
                this.taskId = setInterval(() => {
                  animateTo(
                    { duration: 500 },
                    () => {
                      if (this.fishX >= this.fishSize) {
                        this.src = $r('app.media.fish_rev')
                        this.fishX -= this.speed
                      }
                    }
                  )
                }, 200)
              }
              if (event.type === TouchType.Up) {
                clearInterval(this.taskId)
                this.taskId = -1
              }
            })

          Column({ space: 40 }) {
            // 向上和向下移动,小鱼的身体均不能超出屏幕范围
            Button('↑').backgroundColor('#20101010')
              .onClick(() => {
                if (this.fishY >= this.fishSize) {
                  animateTo(
                    { duration: 500 },
                    () => {
                      this.fishY -= this.speed
                    }
                  )
                }
              })
              .onTouch((event: TouchEvent) => {
                if (event.type === TouchType.Down) {
                  this.taskId = setInterval(() => {
                    animateTo(
                      { duration: 500 },
                      () => {
                        if (this.fishY >= this.fishSize) {
                          this.fishY -= this.speed
                        }
                      }
                    )
                  }, 200)
                }
                if (event.type === TouchType.Up) {
                  console.log("testTag", `停止向上,当前fishY为:${this.fishY}`)
                  clearInterval(this.taskId)
                  this.taskId = -1
                }
              })
            Button('↓').backgroundColor('#20101010')
              .onClick(() => {
                if (this.fishY <= this.screenWidth - this.fishSize) {
                  animateTo(
                    { duration: 500 },
                    () => {
                      this.fishY += this.speed
                    }
                  )
                }
              })
              .onTouch((event: TouchEvent) => {
                if (event.type === TouchType.Down) {
                  this.taskId = setInterval(() => {
                    animateTo(
                      { duration: 500 },
                      () => {
                        if (this.fishY <= this.screenWidth - this.fishSize) {
                          this.fishY += this.speed
                        }
                      }
                    )
                  }, 200)
                }
                if (event.type === TouchType.Up) {
                  console.log("testTag", `停止向下,当前fishY为:${this.fishY}`)
                  clearInterval(this.taskId)
                  this.taskId = -1
                }
              })
          }

          Button('→').backgroundColor('#20101010')
            .onClick(() => {
              if (this.fishX <= this.screenHeight - this.fishSize) {
                animateTo(
                  { duration: 500 },
                  () => {
                    this.src = $r('app.media.fish')
                    this.fishX += this.speed
                  }
                )
              }
            })
            .onTouch((event: TouchEvent) => {
              if (event.type === TouchType.Down) {
                this.taskId = setInterval(() => {
                  animateTo(
                    { duration: 500 },
                    () => {
                      if (this.fishX <= this.screenHeight - this.fishSize) {
                        this.src = $r('app.media.fish')
                        this.fishX += this.speed
                      }
                    }
                  )
                }, 200)
              }
              if (event.type === TouchType.Up) {
                clearInterval(this.taskId)
                this.taskId = -1
              }
            })

        }
        .height(240)
        .width(240)
        .justifyContent(FlexAlign.Center)
        .position({ x: 0, y: 120 })
      }
      .height('100%').width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundImage($r('app.media.underwater_cartoon'))
    .backgroundImageSize({ height: '100%', width: '100%' })

  }
}

四、B站视频链接:

鸿蒙应用开发学习:改进小鱼动画实现按键一直按下时控制小鱼移动和限制小鱼移出屏幕-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【纯CSS特效源码】(二)精美的立体字

1.漂浮感立体 关键处&#xff1a; text-shadow:2px -2px white, -6px 6px gray;给字体添加了两层shadow&#xff0c;右上角白色提亮&#xff0c;左下角灰色阴影。 参数解释&#xff1a;例子中2px -2px white&#xff0c;代表右上角白色 第一个参数2px&#xff1a;正数表示从左…

C++ 完成Client分页显示log

分页显示t_log 1、获取用户的输入 1.1、写一个Input成员函数&#xff0c;处理输入进来的语句 std::string XClient::Input() {//清空缓冲//cin.ignore(4096, \n);string input "";for (;;){char a getchar();if (a < 0 || a \n || a \r)break;cout <<…

基于鸿蒙HarmonyOS 元服务开发一款公司运营应用(ArkTS API 9)

前言 最近基于Harmony OS最新版本开发了一个作品&#xff0c;本文来详细讲解一下&#xff0c;如何我是如何开发这个作品的。以及如何使用OpenHarmony&#xff0c;基于ArkTS&#xff0c;API 9来开发一个属于自己的元服务。 废话不多说&#xff0c;我的作品名称叫做Company Oper…

Spring Boot 中实现文件上传、下载、删除功能

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

【RPC】序列化:对象怎么在网络中传输?

今天来聊下RPC框架中的序列化。在不同的场景下合理地选择序列化方式&#xff0c;对提升RPC框架整体的稳定性和性能是至关重要的。 一、为什么需要序列化&#xff1f; 首先&#xff0c;我们得知道什么是序列化与反序列化。 网络传输的数据必须是二进制数据&#xff0c;但调用…

Jenkins-Maven Git

整合Maven 安装GIT #更新yum sudo yum update #安装git yum install git 安装Maven插件,在插件管理中心&#xff1a; 配置仓库 配置密码认证 我们可以在这个目录下看到Jenkins 帮我们拉取了代码 /env/liyong/data/docker/jenkins_mount/workspace/maven-job 配置maven打包…

江科大STM32 下

目录 ADC数模转换器DMA直接存储器存取USART串口9-2 串口发送接受9-3 串口收发HEX数据包 I2CSPI协议10.1 SPI简介W25Q64简介10.3 SPI软件读写W25Q6410.4 SPI硬件读写W25Q64 BKP、RTC11.0 Unix时间戳11.1 读写备份寄存器BKP11.2 RTC实时时钟 十二、PWR12.1 PWR简介12.2 修改主频1…

Scratch优秀作品飞翔小鸟

程序说明&#xff1a;在无尽的划痕堆中飞驰而过随着你越来越多地飞进迷宫般的街区&#xff0c;平台变得越来越难。 演示视频 scratch飞翔小鸟 其实这就是一个类似像素小鸟的程序&#xff0c;只不过水管角色就地取材&#xff0c;使用scratch里面的积木图片拼成了水管&#xff0…

爬虫案例—抓取豆瓣电影的电影名称、评分、简介、评价人数

爬虫案例—抓取豆瓣电影的电影名称、评分、简介、评价人数 豆瓣电影网址&#xff1a;https://movie.douban.com/top250 主页截图和要抓取的内容如下图&#xff1a; 分析&#xff1a; 第一页的网址&#xff1a;https://movie.douban.com/top250?start0&filter 第二页的…

文献阅读:Large Language Models as Optimizers

文献阅读&#xff1a;Large Language Models as Optimizers 1. 文章简介2. 方法介绍 1. OPRO框架说明2. Demo验证 1. 线性回归问题2. 旅行推销员问题&#xff08;TSP问题&#xff09; 3. Prompt Optimizer 3. 实验考察 & 结论 1. 实验设置2. 基础实验结果 1. GSM8K2. BBH3.…

linux建立基本网站

网站需求&#xff1a; 1.基于域名[www.openlab.com]可以访问网站内容为 welcome to openlab!!! 2.给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料和缴费网站&#xff0c;基于[www.openlab.com/student] 网站访问学生信息 [www.openlab.com/data]网站访问教学资…

微机原理常考填空以及注意事项

以下&#xff1a; 1&#xff0c;两条高位地址线未参加地址译码&#xff0c;则对应的地址范围它的容量是多少倍&#xff1f; 答&#xff1a;公式CPU的地址线&#xff08;假设16位&#xff09;&#xff08;它的低位地址线一般进入片内A0~A10&#xff0c;高位A11就是A、A12就是B、…

微信小程序(一)简单的结构及样式演示

注释很详细&#xff0c;直接上代码 涉及内容&#xff1a; view和text标签的使用类的使用flex布局水平方向上均匀分布子元素垂直居中对齐子元素字体大小文字颜色底部边框的宽和颜色 源码&#xff1a; index.wxml <view class"navs"><text class"active…

任务7:安装MySQL数据库

任务描述 知识点&#xff1a; MySQL数据库安装与使用 重 点&#xff1a; 基于CentOS系统&#xff0c;安装MySQL数据库 内 容&#xff1a; 安装MySQL数据库修改root用户密码 任务指导 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c…

【汽车销售数据】2015~2023年各厂商各车型的探索 数据分析可视化

数据处理的思路&#xff1a; 1 各表使用情况&#xff1a; 汽车分厂商每月销售表&#xff0c;该表主要分析展示top10销量的厂商销量、占比变化情况&#xff08;柱形图、饼图&#xff09;&#xff1b;中国汽车分车型每月销售量表&#xff0c;该表主要分析展示top20销量的车型销…

UML-顺序图

提示&#xff1a;用例图从参与者的角度出发&#xff0c;描述了系统的需求&#xff08;用例图&#xff09;&#xff1b;静态图定义系统中的类和对象间的静态关系&#xff08;类图、对象图和包图&#xff09;&#xff1b;状态机模型描述系统元素的行为和状态变化流程&#xff08;…

计算机体系结构基础复习

1. 计算机系统可划分为哪几个层次,各层次之间的界面是什么? 你认为这样划分层次的意义何在? 答&#xff1a; 计算机系统可划分为四个层次&#xff0c;分别是&#xff1a;应用程序、 操作系统、 硬件系统、 晶体管四个大的层次。 注意把这四个层次联系起来的三个界面。各层次…

css 怎么绘制一个带圆角的渐变色的边框

1&#xff0c;可以写两个样式最外面的div设置一个渐变的背景色。里面的元素使用纯色。但是宽高要比外面元素的小。可以利用里面的元素设置padding这样挡住部分渐变色。漏出来的渐变色就像边框一样。 <div class"cover-wrapper"> <div class"item-cover…

春节回家前,请一定给你的电脑装上KKView远程控制软件

马上春节了&#xff0c;电脑不能带回家&#xff0c;有时候要处理点意外的事情&#xff0c;怎么办&#xff1f;只要走之前&#xff0c;给你电脑装上KKView远程控制软件&#xff0c;就可以随时随地用手机或电脑控制你的工作电脑&#xff0c;远程办公、传文件、看摄像头都没问题。…

人脸识别为何老是不过?是什么原因导致的?

人脸识别可能无法通过的原因有很多&#xff0c;以下是可能的一些原因&#xff1a; 1. 非常规面部表情&#xff1a;如果你做出了与常规面部表情不同的表情&#xff0c;如张大嘴巴或瞪大眼睛等&#xff0c;可能会干扰人脸识别系统的准确性。 2. 光线条件&#xff1a;人脸识别系统…