鸿蒙小案例-你画我猜

鸿蒙小案例-你画我猜

1.准备组件(组件布局)
2.实现跟随鼠标画笔画出图案功能
3.实现复制上面的画笔的图案功能
4.其他小功能

1.组件的准备

画布的组件官方给的API是Canvas,需要传递一个参数CanvasRenderingContext2D
在这里插入图片描述
直接搜索API 使用官方案例

  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

   Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#ffff00')
        .onReady(() => {
          this.context.fillRect(0, 30, 100, 100)
        })
    }
    .width('100%')
    .height('100%')

因为我们参数描述到

不支持多个Canvas共用一个CanvasRenderingContext2D对象

所以,结合我们的显示区域,基础代码精简为

@Entry
@Preview
@Component
struct Nihuawocai2 {
  private context01: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))
  private context02: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))

  /**
   * 1.准备组件(画布布局)
   * 2.实现跟随鼠标画笔画出图案
   * 3.实现复制上面的画笔的图案
   * 4.其他小功能
   */
  build() {
    Row() {
      Column() {
        //自己绘画的区域
        Row(){
          Canvas(this.context01)
            .width('100%')
            .height('100%')
            .backgroundColor(Color.White)
            .onReady(() => {
              //this.context01.fillRect(0, 30, 100, 100)
            })
        }.height('40%').border({ width: { bottom:5 },color:Color.Red })
        //复制绘画的区域
        Row(){
          Canvas(this.context02)
            .width('100%')
            .height('100%')
            .backgroundColor(Color.Grey)
            .onReady(() => {
              //this.context02.fillRect(0, 30, 100, 100)
            })
        }.height('40%')
        //功能区
        Row(){
          Button("清屏")
            .onClick(() =>
            {

            })

        }.height('20%')
      }.width('100%')
    }.height('100%')
  }
}

实现效果:
在这里插入图片描述

2.实现跟随鼠标画笔画出图案

画笔呢肯定是需要用到触摸事件,API如下
在这里插入图片描述
所以Canvas增加onTouch事件

 Canvas(this.context01)
     .width('100%')
     .height('100%')
     .backgroundColor(Color.White)
     .onTouch((event: TouchEvent) =>{

    })

当触摸事件是按下时,开始绘画
在这里插入图片描述
在这里插入图片描述
所以onTouch增加代码

.onTouch((event: TouchEvent) =>{
              //按下时触发,开始绘画
              if (event.type === TouchType.Down)
              {
                  AlertDialog.show({message:'按下手指'})
              }
              //抬起时触发  结束绘画
              if (event.type === TouchType.Up)
              {
                AlertDialog.show({message:'抬起手指'})
              }
              //移动时触发  正在绘画
              if (event.type === TouchType.Move)
              {
                AlertDialog.show({message:'移动手指'})
              }
            })

预览器测试一下,发现 移动手指会一直显示,说明这个触发是没问题的

接下来首先理一下绘画的思路

按下时,准备绘画,从按下的坐标点开始

移动时,正在绘画,随着移动的轨迹,不停记录坐标点,链接上一个坐标点到新坐标点

抬起时,结束绘画,记录当前坐标点为结束点

可能会有多次按下,抬起的操作

所以,我们需要增加一个坐标类,再给一个是否起始点的布尔值

//坐标对象
class zbClass{
  x:number = 0
  y:number = 0
  //按下时记录true,移动时不记录,抬起时记录false
  isStart?:boolean = false
}

增加常量:

是否开始绘画,用来区分多次按下的操作

坐标集合,用来记录绘画轨迹坐标点

//是否开始绘画
isDraw:boolean = false
//坐标点 集合
zbList: zbClass[] = [] 

按下时,记录当前坐标,并增加当前坐标到坐标集合中

//按下时触发,开始绘画
if (event.type === TouchType.Down)
{
    this.isDraw = true
    this.context01X  = event.touches[0].x
    this.context01Y  = event.touches[0].y
    this.zbList.push({
        x:this.context01X,
        y:this.context01Y,
        isStart:true
    })
    //开始绘画
	this.context01.beginPath()
}

开始绘画,参考CanvasRenderingContext2D API官方案例,既将画笔从一个点连接到另一个点,然后不停循环
在这里插入图片描述
将绘画写成一个方法,直接去调用

//移动时触发  正在绘画
if (event.type === TouchType.Move)
{
    if (this.isDraw)
    {
        //绘画中
        this.drawIng(event.touches[0].x, event.touches[0].y)
    }
}

drawIng方法

//绘画过程
  drawIng(x: number, y: number)
  {
      //先移动画笔到起始点
    this.context01.moveTo(this.context01X,this.context01Y)
     //设置绘画边框宽度
    this.context01.lineWidth = 5
    //将画笔从上一个坐标 链接到 手指移动到的新坐标
    this.context01.lineTo(x,y)
    //更新常量坐标点为手指移动坐标点,随着手指移动,形成循环
    this.context01X = x
    this.context01Y = y
    //因为有复制操作,所以,需要保存坐标点
    this.zbList.push({
      x:x,
      y:y
    })
    this.context01.stroke()
  }

抬起手指操作

//抬起时触发  结束绘画
if (event.type === TouchType.Up)
{
    //当前按下手指周期,绘画结束
    this.isDraw = false
    //记录当前周期的结束坐标
    this.zbList.push({
        x: event.touches[0].x,
        y: event.touches[0].y,
        isStart:false
    })
    this.context01.closePath()
}

此时通过预览器测试一下,基本功能已经实现,而且抬起再按下也能继续绘画了

3.实现复制上面的画笔的图案

复制动作可以在全部绘画完后,统一复制,也可以在绘画的同时延迟复制

事后统一复制也就是将集合中的点全部连一遍,比较简单,所以我们边画边复制,在抬起一次手指时开始复制
增加常量:

 //复制画,坐标点
  context02X: number = 0
  context02Y: number = 0
  //定时器,用来循环
  timer: number = -1

增加一个复制方法

//复制动作
cpDraw()
{
  this.context02.lineWidth = 5
  this.timer = setInterval(() =>
  {
    if (this.zbList.length === 0)
    {
      clearInterval(this.timer)
      this.timer = -1
      return
    }
    let p = this.zbList.shift()
    if (p.isStart)
    {
      this.context02.closePath()
      this.context02.beginPath()
      this.context02X = p.x
      this.context02Y = p.y
    } else
    {
      //移动画笔
      this.context02.moveTo(this.context02X, this.context02Y)
      //链接点
      this.context02.lineTo(p.x, p.y)
      //更新点
      this.context02X = p.x
      this.context02Y = p.y
      this.context02.stroke()
    }
  }, 100)
}

测试功能,一切OK

4.其他小功能

清理屏幕
将两个画布的坐标点全部都设置为初始点

Button("清屏")
    .onClick(() =>
    {
        this.context01.clearRect(0, 0, 360, 300)
        this.context02.clearRect(0, 0, 360, 300)
        this.zbList = []
    })

完整代码

@Entry
@Preview
@Component
struct Nihuawocai2 {
  private context01: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))
  private context02: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))

  //第一个画布的坐标信息
  context01X:number = 0
  context01Y:number = 0
  //是否开始绘画
  isDraw:boolean = false
  //坐标点 集合
  zbList: zbClass[] = []

  //下方绘画坐标点
  context02X: number = 0
  context02Y: number = 0
  //定时器,用来循环
  timer: number = -1
  //绘画过程
  drawIng(x: number, y: number)
  {
    //先移动画笔到起始点
    this.context01.moveTo(this.context01X,this.context01Y)
    //将画笔从上一个坐标 链接到 手指移动到的新坐标
    this.context01.lineTo(x,y)
    //更新常量坐标点为手指移动坐标点,随着手指移动,形成循环
    this.context01X = x
    this.context01Y = y
    //因为有复制操作,所以,需要保存坐标点
    this.zbList.push({
      x:x,
      y:y
    })
    this.context01.stroke()
  }

  //复制动作
  cpDraw()
  {
    this.timer = setInterval(() =>
    {
      if (this.zbList.length === 0)
      {
        clearInterval(this.timer)
        this.timer = -1
        return
      }
      let p = this.zbList.shift()
      if (p.isStart)
      {
        this.context02.closePath()
        this.context02.beginPath()
        this.context02X = p.x
        this.context02Y = p.y
      } else
      {
        //移动画笔
        this.context02.moveTo(this.context02X, this.context02Y)
        //链接点
        this.context02.lineTo(p.x, p.y)
        //更新点
        this.context02X = p.x
        this.context02Y = p.y
        this.context02.stroke()
      }
    }, 100)
  }


  /**
   * 1.准备组件(画布布局)
   * 2.实现跟随鼠标画笔画出图案
   * 3.实现复制上面的画笔的图案
   * 4.其他小功能
   */
  build() {
    Row() {
      Column() {
        //自己绘画的区域
        Row(){
          Canvas(this.context01)
            .width('100%')
            .height('100%')
            .backgroundColor(Color.White)
            .onTouch((event: TouchEvent) =>{
              //按下时触发,开始绘画
              if (event.type === TouchType.Down)
              {
                //当前按下手指周期,绘画开始
                this.isDraw = true
                this.context01X  = event.touches[0].x
                this.context01Y  = event.touches[0].y
                this.zbList.push({
                  x:this.context01X,
                  y:this.context01Y,
                  isStart:true
                })
                //开始绘画
                this.context01.beginPath()

              }
              //抬起时触发  结束绘画
              if (event.type === TouchType.Up)
              {
                //当前按下手指周期,绘画结束
                this.isDraw = false
                this.zbList.push({
                  x: event.touches[0].x,
                  y: event.touches[0].y,
                  isStart:false
                })
                this.context01.closePath()
                this.cpDraw()
              }
              //移动时触发  正在绘画
              if (event.type === TouchType.Move)
              {
                if (this.isDraw)
                {
                  //绘画中
                  this.drawIng(event.touches[0].x, event.touches[0].y)
                }
              }
            })
            .onReady(() => {
              //设置绘画边框宽度
              this.context01.lineWidth = 5
            })
        }.height('40%').border({ width: { bottom:5 },color:Color.Red })
        //复制绘画的区域
        Row(){
          Canvas(this.context02)
            .width('100%')
            .height('100%')
            .backgroundColor(Color.Grey)
            .onReady(() => {
              //设置绘画边框宽度
              this.context02.lineWidth = 5
            })
        }.height('40%')
        //功能区
        Row(){
          Button("清屏")
            .onClick(() =>
            {
              this.context01.clearRect(0, 0, 360, 300)
              this.context02.clearRect(0, 0, 360, 300)
              this.zbList = []
            })

        }.height('20%')
      }.width('100%')
    }.height('100%')
  }
}

//坐标对象
class zbClass{
  x:number = 0
  y:number = 0
  //按下时记录true,移动时不记录,抬起时记录false
  isStart?:boolean = false
}

使用模拟器测试功能OK
模拟器效果
在这里插入图片描述
— end

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

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

相关文章

小技巧 | 如何将win11回退至win10

当你不小心点错将电脑的win10系统更新成win11系统了(但没有完全更新),你会怎么做呢? 1.在“开始”菜单界面点击“设置”选项 2.点击“更新和安全”选项 3.在“更新历史记录”中点击“恢复选项” 4.点击“返回”选项 会弹出以下界面…

three.js 细一万倍教程 从入门到精通(二)

目录 三、全面认识three.js物体 3.1、掌握几何体顶点_UV_法向属性 3.2、BufferGeometry设置顶点创建矩形 3.3、生成酷炫三角形科技物体 四、详解材质与纹理 4.1、初识材质与纹理 4.2、详解纹理偏移_旋转_重复 偏移 旋转 重复 4.3、设置纹理显示算法与mipmap mapFil…

【动态规划】:泰波那契模型_解码方法

朋友们、伙计们,我们又见面了,本专栏是关于各种算法的解析,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数据结构专栏&…

【网工】华为设备命令学习(综合实验一)

实验要求和实验成果如图所示。 LSW2不需要其他配置&#xff0c;其下就一台设备&#xff0c;不需要区分。 LSW3配置如下&#xff1a; <Huawei>sy Enter system view, return user view with CtrlZ. [Huawei]un in en //关闭系统提示信息 Info: Information …

LeetCode、72. 编辑距离【中等,二维DP】

文章目录 前言LeetCode、72. 编辑距离【中等&#xff0c;二维DP】题目链接与分类二维DP 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖技术内容…

VTK Python PyQt 监听键盘 控制 Actor 移动 变色

KeyPressInteractorStyle 在vtk 中有时我们需要监听 键盘或鼠标做一些事&#xff1b; 1. 创建 Actor&#xff1b; Sphere vtk.vtkSphereSource() Sphere.SetRadius(10)mapper vtk.vtkPolyDataMapper() mapper.SetInputConnection(Sphere.GetOutputPort()) actor vtk.vtkAc…

Vue核心基础6:Vue内置指令、自定义指令、生命周期

1 Vue中的内置指令 <script>const vm new Vue({el: #root,data: {n: 1,m: 100,name: Vue,str: <h3>你好</h3>}})</script> 1.1 v-text <div v-text"name"></div>1.2 v-html <div v-html"str"></div> …

Spring Boot 笔记 012 创建接口_添加文章分类

1.1.1 实体类添加校验 package com.geji.pojo;import jakarta.validation.constraints.NotEmpty; import lombok.Data;import java.time.LocalDateTime;Data public class Category {private Integer id;//主键IDNotEmptyprivate String categoryName;//分类名称NotEmptypriva…

中小学信息学奥赛CSP-J认证 CCF非专业级别软件能力认证-入门组初赛模拟题第一套(完善程序题)

CCF认证CSP-J入门组模拟测试题第一套 三、完善程序题 第一题 九宫格 请完善下面的程序,将1~9个数字分别填人3x3的九宫格中,第一行的三个数字组成一个三位数。要使第二行的三位数是第一行的2倍,第三行的三位数是第一行的3倍且每个格子里的数字都不能重复,现在要求输出所有的填…

python输出字符 2022年12月青少年电子学会等级考试 中小学生python编程等级考试二级真题答案解析

目录 python输出字符 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python输出字符 2022年12月 python编程等级考试级编程题 一、题目要求 …

《CSS 简易速速上手小册》第2章:CSS 布局与定位(2024 最新版)

文章目录 2.1 Flexbox&#xff1a;灵活的布局解决方案2.1.1 基础知识2.1.2 重点案例&#xff1a;创建一个响应式导航菜单2.1.3 拓展案例 1&#xff1a;卡片布局2.1.4 拓展案例 2&#xff1a;中心对齐的登录表单 2.2 Grid 布局&#xff1a;网格系统的魔力2.2.1 基础知识2.2.2 重…

渗透测试练习题解析 3(CTF web)

1、[网鼎杯 2020 朱雀组]phpweb 1 考点&#xff1a;反序列化漏洞利用 进入靶场&#xff0c;查看检查信息&#xff0c;发现存在两个参数 func 和 p 查看页面源代码 payload&#xff1a;funcfile_get_contents&pphp://filter/resourceindex.php 整理后&#xff0c;就是 PHP 代…

数据结构与算法:单链表

朋友们大家好&#xff0c;本节来到数据结构与算法的新内容&#xff1a;单链表 在上篇文章中&#xff0c;我们知道顺序表通常需要预分配一个固定大小的内存空间&#xff0c; 通常以二倍的大小进行增容&#xff0c;可能会造成空间的浪费&#xff0c;本篇文章我们介绍的链表可以解…

去除vue自带的边距

使用vue时发现总有去不掉的外边距&#xff0c;在index.vue里面怎样设置样式都不管用 查阅资料后发现要在vue项目自带的index.html文件内添加下面的样式代码才行 <style>*{margin: 0;padding: 0;}body,html{margin: 0;padding: 0;} </style>

二、DataX安装

DataX安装 一、简介二、系统要求三、部署 一、简介 官方地址&#xff1a;https://github.com/alibaba/DataX/blob/master/userGuid.md 二、系统要求 LinuxJDK(1.8以上&#xff0c;推荐1.8) Centos7.9的java1.8安装命令&#xff1a;yum install java-1.8.0-openjdk.x86_64 Py…

【新书推荐】7.6节 相对基址加变址寻址方式

本节内容&#xff1a;基址加变址寻址方式。 ■基址加变址寻址方式&#xff1a;指令操作数为内操作数&#xff0c;操作数地址使用[基址寄存器变址寄存器]表示。 7.6.1 基址加变址寻址方式 基址加变址寻址方式的操作数在存储器中&#xff0c;操作数的有效地址由基地址寄存器&am…

day 20(补2.5)

fread 函数&#xff1a; 今日练习 C语言面试题5道~ 1. static 有什么用途&#xff1f;&#xff08;请至少说明两种&#xff09; 1) 限制变量的作用域 2) 设置变量的存储域 2. 引用与指针有什么区别&#xff1f; 1) 引用必须被初始化&#xff0c;指针不必。 2) 引用初始…

幻兽帕鲁服务器原来的存档不想玩了,怎么清档?如何重来?

如果需要备份原存档的话&#xff0c;就先把存档导出来备份。或者手动去服务器文件里找到游戏存档文件夹&#xff0c;保存下载。 如无需备份原存档&#xff0c;则可以直接使用幻兽帕鲁应用模板&#xff0c;来重装服务器的操作系统。 方法很简单&#xff1a; 详细教程地…

mysql经典4张表问题

1.数据库表结构关联图 2.问题&#xff1a; 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数3.查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩4、查询名字中含有"风"字的学生信息5、查询课程名称为"数学"&…

网络协议与攻击模拟_17HTTPS 协议

HTTPShttpssl/tls 1、加密算法 2、PKI&#xff08;公钥基础设施&#xff09; 3、证书 4、部署HTTPS服务器 部署CA证书服务器 5、分析HTTPS流量 分析TLS的交互过程 一、HTTPS协议 在http的通道上增加了安全性&#xff0c;传输过程通过加密和身份认证来确保传输安全性 1、TLS …
最新文章