当前位置:   article > 正文

鸿蒙小案例-你画我猜

鸿蒙小案例-你画我猜

鸿蒙小案例-你画我猜

1.准备组件(组件布局)
2.实现跟随鼠标画笔画出图案功能
3.实现复制上面的画笔的图案功能
4.其他小功能
  • 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%')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

因为我们参数描述到

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

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

@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%')
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

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

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

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

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

    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

当触摸事件是按下时,开始绘画
在这里插入图片描述
在这里插入图片描述
所以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:'移动手指'})
              }
            })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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

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

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

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

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

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

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

//坐标对象
class zbClass{
  x:number = 0
  y:number = 0
  //按下时记录true,移动时不记录,抬起时记录false
  isStart?:boolean = false
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

增加常量:

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

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

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

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

//按下时触发,开始绘画
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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

//移动时触发  正在绘画
if (event.type === TouchType.Move)
{
    if (this.isDraw)
    {
        //绘画中
        this.drawIng(event.touches[0].x, event.touches[0].y)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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()
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

抬起手指操作

//抬起时触发  结束绘画
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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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

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

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

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

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

增加一个复制方法

//复制动作
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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

测试功能,一切OK

4.其他小功能

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

Button("清屏")
    .onClick(() =>
    {
        this.context01.clearRect(0, 0, 360, 300)
        this.context02.clearRect(0, 0, 360, 300)
        this.zbList = []
    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

完整代码

@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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/98210
推荐阅读