用户3116712
用户3116712
  • 发布:52 分钟前
  • 更新:52 分钟前
  • 阅读:8

如何在Canvas上实现涂抹效果

分类:HBuilder

问题现象
在移动应用开发中,屏幕涂抹交互(如签名、涂鸦、擦除)是提升用户体验的关键功能。HarmonyOS的Canvas组件结合触摸事件监听与手势识别,为开发者提供了低门槛、高性能的2D图形绘制能力。本文将通过以下常见应用场景,详解如何在Canvas上实现涂抹效果:

场景一:如何结合手势或者事件实现滑动路径绘制?
场景二:如何撤销已绘制的路径?
场景三:如何擦除部分绘制内容?
背景知识
Canvas:提供画布组件,用于自定义绘制图形,开发者使用CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象在Canvas组件上进行绘制,绘制对象可以是基础形状、文本、图片等。
lineTo:从当前点到指定点进行路径连接。
globalCompositeOperation:设置合成操作的方式,默认值为source-over。
onTouch:手指触摸动作触发该回调。可以获取滑动过的路径坐标点。
PanGesture:滑动手势事件,当滑动的最小距离达到设定的最小值时触发滑动手势事件。
解决方案
场景一:结合手势或者事件实现路径绘制。
Canvas组件可以绑定触摸事件和滑动手势来获取手指按压时的坐标,在事件触发过程中可以根据event对象获取到在屏幕上触摸的点,再结合Canvas的lineTo方法就可以把手指移动过程中的路径给记录下来,达到手指滑动屏幕就绘制的效果。

onTouch实现如下:
@Entry
@Component
struct CanvasTouch {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);

build() {
Column() {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor($r('sys.color.comp_background_focus'))
.onReady(() => {
this.context.lineWidth = 10;
this.context.strokeStyle = '#0000ff';
})
.onTouch((event: TouchEvent) => {
// 获取到触摸的坐标点
let x = event.touches[0].x;
let y = event.touches[0].y;
if (event.type == TouchType.Down) {
// 手指按下时画布移动到当前坐标点
this.context.beginPath();
this.context.moveTo(x, y);
}
if (event.type === TouchType.Move) {
// 手指移动时画布用线条连接到当前坐标点
this.context.lineTo(x, y);
this.context.stroke();
}
if (event.type === TouchType.Up) {
// 手指抬起时生成闭合路径
this.context.closePath();
}
})
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]);
};
}
}
PanGesture实现如下:
@Entry
@Component
struct CanvasPanGesture {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);

build() {
Column() {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor($r('sys.color.comp_background_focus'))
.onReady(() => {
this.context.lineWidth = 10;
this.context.strokeStyle = '#0000ff';
})
.gesture(
PanGesture({ fingers: 1 })
.onActionStart((event: GestureEvent) => {
let x = event.fingerList[0].localX;
let y = event.fingerList[0].localY;
// 手指按下时画布移动到当前坐标点
this.context.beginPath();
this.context.moveTo(x, y);
})
.onActionUpdate((event: GestureEvent) => {
let x = event.fingerList[0].localX;
let y = event.fingerList[0].localY;
// 手指移动时画布用线条连接到当前坐标点
this.context.lineTo(x, y);
this.context.stroke();
})
.onActionEnd(() => {
// 手指抬起时生成闭合路径
this.context.closePath();
})
)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]);
};
}
}
实现效果如下:

点击放大

场景二:撤销绘制的路径。
在一些签名场景,如果用户绘制错误需要重新绘制,直接使用clearRect方法清空画布体验不够友好,需要仅撤销最新的绘制路径,这时可以使用数组来存储绘制过程中的路径,然后点击撤销时移除最新路径,最后重绘剩余路径,这样即可实现撤销绘制功能。示例代码参考如下:

interface Point {
x: number;
y: number;
}

export class DrawingPath {
points: Point[] = [];
}

@Entry
@Component
struct CanvasCancelDraw {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private paths: DrawingPath[] = [];

build() {
Column() {
Canvas(this.context)
.width('100%')
.height('570vp')
.borderRadius(16)
.backgroundColor($r('sys.color.comp_background_focus'))
.onReady(() => {
this.context.lineWidth = 10;
this.context.strokeStyle = '#0000ff';
})
.onTouch((event: TouchEvent) => {
let x = event.touches[0].x;
let y = event.touches[0].y;
if (event.type == TouchType.Down) {
// 按下时新建一条路径
const path = new DrawingPath();
path.points.push({ x: x, y: y });
this.paths.push(path);
this.context.beginPath();
this.context.moveTo(x, y);
}
if (event.type === TouchType.Move) {
// 移动时把当前的坐标点放入最新的路径中
this.paths[this.paths.length - 1].points.push({ x: x, y: y });
this.context.lineTo(x, y);
this.context.stroke();
}
if (event.type === TouchType.Up) {
this.context.closePath();
}
});

  Row({ space: 20 }) {  
    Button('清空')  
      .layoutWeight(1)  
      .onClick(() => {  
        this.paths = [];  
        this.context.clearRect(0, 0, this.context.width, this.context.height);  
      });  
    Button('撤销')  
      .layoutWeight(1)  
      .onClick(() => {  
        if (this.paths.length < 1) {  
          return;  
        }  
        this.paths.pop()!!;  
        this.context.clearRect(0, 0, this.context.width, this.context.height);  
        // 重绘保存的路径  
        this.paths.forEach((path) => {  
          if (path.points.length < 1) {  
            return;  
          }  
          this.context.beginPath();  
          this.context.moveTo(path.points[0].x, path.points[0].y);  
          for (let i = 0; i < path.points.length; i++) {  
            this.context.lineTo(path.points[i].x, path.points[i].y);  
            this.context.stroke();  
          }  
          this.context.closePath();  
        });  
      });  
  }.width('100%')  
  .justifyContent(FlexAlign.Center)  
  .margin(20);  
}.padding(16);  

}
}
https://coub.com/embed/kwki4m8ihy
https://coub.com/embed/1dc59ftpsz
https://coub.com/embed/1eg6k9knxq
https://coub.com/embed/ffcvsoqgy9
https://coub.com/embed/mtf20e2xfs
https://coub.com/embed/vcdyj2hsux
https://coub.com/embed/p8u435h7k0
https://coub.com/embed/53uc97iqzh
https://coub.com/embed/slklk9dip7
https://coub.com/embed/x5r8qua9dn
https://coub.com/embed/suzzf1tabm
https://coub.com/embed/iwlz1k4x5c
https://coub.com/embed/esio81b16u
https://coub.com/embed/08isxtzg6y
https://coub.com/embed/5t2ou1h0u1
https://coub.com/embed/2i826b72cf
https://coub.com/embed/wl4g0a80wd
https://coub.com/embed/noxtktrsld
https://coub.com/embed/4arm33ehej
https://coub.com/embed/4m5uhixzc6
https://coub.com/embed/z4hni578js
https://coub.com/embed/vc1lp4h9wv
https://coub.com/embed/ahq7q7smb9
https://coub.com/embed/s3agn3nkdx
https://coub.com/embed/0tpmvd839f
https://coub.com/embed/a52spj6rs2
https://coub.com/embed/mytvxbwrus
https://coub.com/embed/hto4op5jpb
https://coub.com/embed/5i13w22bho
https://coub.com/embed/ng8whwdnmh
https://coub.com/embed/4tepeaanko
https://coub.com/embed/gq6dpvlatn
https://coub.com/embed/n0xesp3qe7
https://coub.com/embed/i4ciaef3z2
https://coub.com/embed/h6tzz4imsh
https://coub.com/embed/5oh9y0o849
https://coub.com/embed/di1lvxi6rs
https://coub.com/embed/dvr0d1spum
https://coub.com/embed/a0chxn6q37
https://coub.com/embed/9kdpqt8gi3
https://coub.com/embed/wwtpzdcshr
https://coub.com/embed/i3j774nb78
https://coub.com/embed/9vdne44f87
https://coub.com/embed/di14nasb4i
https://coub.com/embed/tjdbi2z10f
https://coub.com/embed/xymgbl98l3
https://coub.com/embed/d46w9vg6y2
https://coub.com/embed/7kjd2r109r
https://coub.com/embed/ewtrtmuecq
https://coub.com/embed/x44fcmuuwa
https://coub.com/embed/ajx3cjloat
https://coub.com/embed/s9xf0u8gl8
https://coub.com/embed/9ogtzmbj73
https://coub.com/embed/2th49b4ms0
https://coub.com/embed/ke6047rz7q
https://coub.com/embed/m2oqeg89q8
https://coub.com/embed/774g3ow4sb
https://coub.com/embed/7548j9l7nl
https://coub.com/embed/zjz1qsyin2
https://coub.com/embed/xik7e7nili
https://coub.com/embed/zp95r4y15i
https://coub.com/embed/adde9a38t1
https://coub.com/embed/1qarvak9lx
https://coub.com/embed/dko4y9u0yf
https://coub.com/embed/ypw9dtvmab
https://coub.com/embed/8ewvlnn2b6
https://coub.com/embed/5s2dev0lra
https://coub.com/embed/c9fihrkf9u
https://coub.com/embed/xzeak1mhkt
https://coub.com/embed/t9dmppwno6
https://coub.com/embed/fz18zmri11
https://coub.com/embed/75espd6kkd
https://coub.com/embed/x2bbs1j2jb
https://coub.com/embed/fe3fwdnu88
https://coub.com/embed/ckzbjutpkj
https://coub.com/embed/qf0w3gxvy2
https://coub.com/embed/ux4gip7l5a
https://coub.com/embed/qavq5q9b1e
https://coub.com/embed/06dq1lpfmv
https://coub.com/embed/h9okejkccd
https://coub.com/embed/z59288b3bc
https://coub.com/embed/jdsgw25pj5
https://coub.com/embed/20ms41ljxh
https://coub.com/embed/cyjima3av9
https://coub.com/embed/xhymuinpm8
https://coub.com/embed/gqqk4335y1
https://coub.com/embed/9uflyvtfzv
https://coub.com/embed/ogd56p24ng
https://coub.com/embed/zydhfymmc3
https://coub.com/embed/pzd0ac0kg5
https://coub.com/embed/obdv3r4cy0
https://coub.com/embed/ka2mdh07zg
https://coub.com/embed/k8417q6t33
https://coub.com/embed/b797hoxnvb
https://coub.com/embed/p3wb9ayf0i
https://coub.com/embed/cylp42xa95
https://coub.com/embed/5vyv5859hb
https://coub.com/embed/uolo157r87
https://coub.com/embed/7bmp0nxmze
https://coub.com/embed/d2q6yzkrli
https://coub.com/embed/zs1hg1bhrv
https://coub.com/embed/yz4tqllp0u
https://coub.com/embed/a2kvibvldp
https://coub.com/embed/09kqx4xcfx
https://coub.com/embed/2c1zyd3kx3
https://coub.com/embed/wep5eg226t
https://coub.com/embed/su365ycwsu
https://coub.com/embed/nzdz5k3kr0
https://coub.com/embed/qg568ebu9j
https://coub.com/embed/md5pqvk50f
https://coub.com/embed/0gt0ay1zk3
https://coub.com/embed/hecylej9t3
https://coub.com/embed/wmxvxv1kkj
https://coub.com/embed/bxxpl0brtv
https://coub.com/embed/pholjf70ut
https://coub.com/embed/m8l2xwwy39
https://coub.com/embed/1c1x2w7t08
https://coub.com/embed/53mubpegym
https://coub.com/embed/on6slxqrt5
https://coub.com/embed/55q881xx6l
https://coub.com/embed/s77w2ok24r
https://coub.com/embed/4e9hy0237n
https://coub.com/embed/3entpjmdbw
https://coub.com/embed/8besg49zbq
https://coub.com/embed/usqat13gtl
https://coub.com/embed/66yxwx6676
https://coub.com/embed/np30bv52rn
https://coub.com/embed/3nk88ivl0b
https://coub.com/embed/83eyn5yj6r
https://coub.com/embed/bymmywq8fr
https://coub.com/embed/9bj0bp5xii
https://coub.com/embed/agvyb0zhme
https://coub.com/embed/8bcvp8upb3
https://coub.com/embed/c8p7zv5zan
https://coub.com/embed/yry7la9tco
https://coub.com/embed/ho2dopbp7j
https://coub.com/embed/amubk2uwuc
https://coub.com/embed/2jwoy1e4u4
https://coub.com/embed/ezz7hv58aq
https://coub.com/embed/sxb8y6f7cm
https://coub.com/embed/y4kvuhob20
https://coub.com/embed/t3iyg4zbk6
https://coub.com/embed/hlu3q922ul
https://coub.com/embed/wr5t1i5hjn
https://coub.com/embed/ig12bx6jem
https://coub.com/embed/elh7b4dm2v
https://coub.com/embed/p3aozbkqis
https://coub.com/embed/1x387gqa9h
https://coub.com/embed/11vq0o0urq
https://coub.com/embed/n95945i2xa
https://coub.com/embed/kwxot0bqpd
https://coub.com/embed/0bzsnthjf8
https://coub.com/embed/l6n7cci0v1
https://coub.com/embed/e33t42b2e8
https://coub.com/embed/uufau92iew
https://coub.com/embed/8nu2gzpi87
https://coub.com/embed/bzvc0eyha5
https://coub.com/embed/m7i31eulsq
https://coub.com/embed/1r27esow61
https://coub.com/embed/v18hqlwcpz
https://coub.com/embed/hltc1g5iav
https://coub.com/embed/eq093ohvb8
https://coub.com/embed/i44t54uooo
https://coub.com/embed/1p2epqlik8
https://coub.com/embed/r7s85h5tgs
https://coub.com/embed/x3a913pgtg
https://coub.com/embed/rm3vt5vimg
https://coub.com/embed/15wu728znl
https://coub.com/embed/2iwy8dlso1
https://coub.com/embed/9ecofudaq2
https://coub.com/embed/odtibqvqqb
https://coub.com/embed/kfit182kgd
https://coub.com/embed/oyuutd8klx
https://coub.com/embed/2ab3tdnsq2
https://coub.com/embed/0lxrs8kij0
https://coub.com/embed/o1b4imc38s
https://coub.com/embed/hmvpibka9g
https://coub.com/embed/pvj08u1amk
https://coub.com/embed/g3fxbal3j0
https://coub.com/embed/hunlqq2jwi
https://coub.com/embed/wsrr0y4x1q
https://coub.com/embed/kg284yqkff
https://coub.com/embed/hbiuts4e7e
https://coub.com/embed/cl8t4qvz2x
https://coub.com/embed/ydk9cyiff7
https://coub.com/embed/ek17k4yytm
https://coub.com/embed/y6t00hom1a
https://coub.com/embed/19q7wp5i00
https://coub.com/embed/4h8bxs9zz7
https://coub.com/embed/jwflpmph2z
https://coub.com/embed/f213jay0fp
https://coub.com/embed/bsf3lctm94
https://coub.com/embed/e83n1arbod
https://coub.com/embed/swembduv5h
https://coub.com/embed/n3fq7zzf5w
https://coub.com/embed/9lio0yr585
https://coub.com/embed/o4fakj61o0
https://coub.com/embed/1hjvwr455z
https://coub.com/embed/xzugpc1qds
https://coub.com/embed/ev7098ev03
https://coub.com/embed/kx4fsmb4b6
https://coub.com/embed/gcorgj2lp8
https://coub.com/embed/gsk38h0x1t
https://coub.com/embed/1gzcnq0drf
https://coub.com/embed/8kk1rohlkq
https://coub.com/embed/95lk677xts
https://coub.com/embed/klzoirlr0i
https://coub.com/embed/ruh9e6e23z
https://coub.com/embed/kaffn57ll3
https://coub.com/embed/wtwakxr59k
https://coub.com/embed/oq7e9iq28m
https://coub.com/embed/xf0mc6ti8q
https://coub.com/embed/ptjtimwt1u
https://coub.com/embed/uu6kt9484i
https://coub.com/embed/1upd83q7xu
https://coub.com/embed/kry12uzw3v
https://coub.com/embed/dtg6xjn98z
https://coub.com/embed/sn0yhm79wv
https://coub.com/embed/9gqnb8624w
https://coub.com/embed/p32o9d4k7v
https://coub.com/embed/e4p0k8n96b
https://coub.com/embed/ordooqx1q4
https://coub.com/embed/w0en3j9kmt
https://coub.com/embed/z925vaal0x
https://coub.com/embed/llsxxio2o3
https://coub.com/embed/xydiujzwro
https://coub.com/embed/2e486z583s
https://coub.com/embed/b850qpvdwf
https://coub.com/embed/uasf7vsd00
https://coub.com/embed/ne9r9ql0ke
https://coub.com/embed/wrb0dawhk3
https://coub.com/embed/e7vo2n3rv0
https://coub.com/embed/sq5lb2quya
https://coub.com/embed/q7er5zdf9c
https://coub.com/embed/hijacyi6zc

0 关注 分享

要回复文章请先登录注册