鸿蒙小案例-你画我猜

news2025/1/19 12:53:30

鸿蒙小案例-你画我猜

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.coloradmin.cn/o/1447372.html

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

相关文章

【GO语言卵细胞级别教程】05.项目创建和函数讲解

感谢!点点赞和评论呀!我将继续更新 目录: 感谢!点点赞和评论呀!我将继续更新0.创建项目1.函数的引入2.注意事项3.详细介绍3.1 形参介绍 4.导入包4.1 基本知识4.2 注意事项 5.init函数6.匿名函数 0.创建项目 创建目录 …

力扣精选算法100道——矩阵区域和 (前缀和专题)

目录 🎈了解题意 🎈算法原理 🎈实现代码 🎈了解题意 给定一个大小为 m x n 的矩阵 mat 和一个整数 k,你需要计算一个新的矩阵 answer,其中每个 answer[i][j] 表示矩阵 mat 中以坐标 (i, j) 为中心、边…

JavaScript 事件循环:Event Loop

🧑‍🎓 个人主页:《爱蹦跶的大A阿》 🔥当前正在更新专栏:《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 事件循环 是 web 开发中的一个核心概念,它是 JavaScript…

【Linux】线程概念和线程控制

线程概念 一、理解线程1. Linux中的线程2. 重新定义线程和进程3. 进程地址空间之页表4. 线程和进程切换5. 线程的优点6. 线程的缺点7. 线程异常8. 线程用途9. 线程和进程 二、线程控制1. pthread 线程库(1)pthread_create()(2)pth…

[Doris] Doris的安装和部署 (二)

文章目录 1.安装要求1.1 Linux操作系统要求1.2 软件需求1.3 注意事项1.4 内部端口 2.集群部署2.1 操作系统安装要求2.2 下载安装包2.3 解压2.4 配置FE2.5 配置BE2.6 添加BE2.7 FE 扩容和缩容2.8 Doris 集群群起脚本 3.图形化 1.安装要求 1.1 Linux操作系统要求 1.2 软件需求 1…

Acwing---842.排列数字

排列数字 1.题目2.基本思想3.代码实现 1.题目 给定一个整数 n,将数字 1∼n排成一排,将会有很多种排列方法。 现在,请你按照字典序将所有的排列方法输出。 输入格式 共一行,包含一个整数 n。 输出格式 按字典序输出所有排列方案…

mysql Day05

sql性能分析 sql执行频率 show global status like Com_______ 慢查询日志 执行时间超过10秒的sql语句 profile详情 show profiles帮助我们了解时间都耗费到哪里了 #查看每一条sql的耗时情况 show profiles#查看指定query_id的sql语句各个阶段的耗时情况 show profile fo…

【电路笔记】-并联电感

并联电感 文章目录 并联电感1、概述2、并联电感示例13、互耦并联电感器4、并联电感示例25、并联电感示例36、总结当电感器的两个端子分别连接到另一个或多个电感器的每个端子时,电感器被称为并联连接在一起。 1、概述 所有并联电感器上的压降将是相同的。 然后,并联的电感器…

MATLAB 1:基础知识

MATLAB中的数据类型主要包括数值类型、逻辑类型、字符串、函数句柄、结构体和单元数组类型。这六种基本的数据类型都是按照数组形式存储和操作的。 MATLAB中还有两种用于高级交叉编程的数据类型,分别是用户自定义的面向对象的用户类类型和Java类类型。 1.1.1数值类…

java微服务面试篇

目录 目录 SpringCloud Spring Cloud 的5大组件 服务注册 Eureka Nacos Eureka和Nacos的对比 负载均衡 负载均衡流程 Ribbon负载均衡策略 自定义负载均衡策略 熔断、降级 服务雪崩 服务降级 服务熔断 服务监控 为什么需要监控 服务监控的组件 skywalking 业务…

【白话前端】快速区分webGL,webGPU,unity3D和UE4

在3D图形渲染的渲染领域,很多友友们对上述概念傻傻分不清,站在前端开发角度,我用简单语言说下,结论在文章最后。 一、四者都能进行3D图形渲染 它们之间有一些区别,下面我将对它们进行简单的区分: WebGPU&a…

【STM32 CubeMX】HAL库的本质读写寄存器

文章目录 前言一、HAL库的本质1.1 HAL库的本质是操作寄存器1.2 自己实现HAL_GPIO_WritePin寄存器通过寄存器的操作点灯代码概况Port bit set/reset register寄存器 总结 前言 在嵌入式系统开发中,HAL(Hardware Abstraction Layer)库是一个重…

HTML世界之第二重天

目录 一、HTML 格式化 1.HTML 文本格式化标签 2.HTML "计算机输出" 标签 3.HTML 引文, 引用, 及标签定义 二、HTML 链接 1.HTML 链接 2.HTML 超链接 3.HTML 链接语法 4.文本链接 5.图像链接 6.锚点链接 7.下载链接 8.Target 属性 9.Id 属性 三、HTML …

GPT4:画一只小怪兽,但是不断升级

请你画一只1级的萌怪兽 请你画一只3级的萌怪兽 请你画一只5级的小怪兽 请你画一只10级的小怪兽 请你画一只50级的怪兽 请你画一只100级的怪兽 怪兽被闪电劈了一下,变成了一只0.1级的可爱小怪兽

UI自动刷新大法:DataBinding数据绑定

之前我们讲了DataBinding在Activity、Fragment、RecyclerView中的基础使用,而那些常规使用方法里,每当绑定的变量发生数据变化时,都需要ViewDataBinding重新设值才会刷新对应UI。而DataBinding通过内部实现的观察者模式来进行自动刷新UI&…

理解JAVA EE设计模式

理解JAVA EE设计模式 在Web应用程序的设计和开发阶段,开发人员在开发类似的项目时可能会遇到相似的问题。每名开发人员可能会遇到的问题找出不同或相似的解决方案。但是,这导致一些时间和精力浪费在为相似的问题寻找解决方案上。因此,要啊节省时间和精力,需要记录常见问题…

基于Spring Boot的足球青训俱乐部管理后台系统,计算机毕业设计(带源码+论文)

源码获取地址: 码呢-一个专注于技术分享的博客平台一个专注于技术分享的博客平台,大家以共同学习,乐于分享,拥抱开源的价值观进行学习交流http://www.xmbiao.cn/resource-details/1757420859554869250

力扣刷题之旅:高阶篇(四)—— 最小生成树算法

力扣(LeetCode)是一个在线编程平台,主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目,以及它们的解题代码。 --点击进入刷题地址 引言: 在算法领域中,图论是一个重要且有趣…

基于 Python 深度学习的电影评论情感分析系统,附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

去空行小工具Html + Javascript

这是一个平常用到的小工具&#xff0c;为了节省屏幕空间把空行去掉&#xff0c;怕要用的时候找不到故记录在此。 效果图 网页版&#xff0c;放在浏览器里就可以用 <!doctype html> <html><head><meta charset"utf-8"><title>去回车…