android画布橡皮,Android画板开发之橡皮擦功能

在上一篇实现了简单的画板功能, 这篇实现橡皮擦功能,首先分析一下应该如何实现,

在andriod有个图像混合(xfermode)概念,利用这个概念我们就可以实现橡皮擦功能。

8b943613bb976434d9214174b8e68d12.gif

一、xfermode

paint有一个方法setxfermode(xfermode),这个方法设置图像的混合模式。参数有三个子类:

avoidxfermode

pixelxorxfermode

porterduffxfermode

前面两个因为不支持硬件加速在api 16已经已经过时弃用了。 简单讲一下第三个。

1.1 porterduffxfermode

该类有且只有一个含参的构造方法porterduffxfermode(porterduff.mode mode),参数就是设置图像的混合模式,下面这张图片形象地说明了各种模式的作用

3eb8918e16aa7d761910773baeb911d7.png

我们的做橡皮擦的时候,就是用到了porterduff.mode.clear这个模式清除图像,所以说橡皮擦也是path,只是绘制的模式不一样了。

二、实现

在上一篇的文章中,实现了最简单笔画画板,就是只有一个画笔模式,所以首先添加一个橡皮擦的绘制模式。

companion object {

const val edit_mode_pen = 0x1l //画笔模式

const val edit_mode_eraser = 0x2l //橡皮擦模式

}

@retention(annotationretention.source)

@intdef(edit_mode_pen, edit_mode_eraser)

annotation class editmode

//当前编辑模式默认为画笔模式

@editmode

private var mmode: long = edit_mode_pen

/**

* 设置画笔模式

*/

fun setmodel(@editmode model:long){

mmode = model

when(model){

edit_mode_pen -> {

//画线

mpaint.xfermode = null

}

edit_mode_eraser ->{

mpaint.xfermode = porterduffxfermode(porterduff.mode.clear)

}

}

}

然后捋一下整个流程:

画笔模式,在ontouch时候画出path,绘制到view上

然后切换到橡皮擦模式,画出path,clear擦掉原来的内容

再来回切换绘制

现在重点是解决第2点,一个path怎么做到不改变原来的path基础上换个绘制模式继续画呢?

如果你考虑第2点的话,效果是这样子的:

what the fuck?(黑人问号) 这什么情况? 其实是因为path只有一条,一直没改变。所以,引入缓存canvas和缓存bitmap,添加两个变量:

//想要绘制的内容先绘制到这个增加的canvas对应的bitmap上,

// 写完后再把这个bitmap的argb信息一次提交给上下文的canvas去绘制

private lateinit var mbufferbitmap: bitmap

private lateinit var mbuffercanvas: canvas

然后在onmeasure中进行初始化:

override fun onmeasure(widthmeasurespec: int, heightmeasurespec: int) {

super.onmeasure(widthmeasurespec, heightmeasurespec)

if(mbuffercanvas == null){

mbufferbitmap = bitmap.createbitmap(measuredwidth, measuredheight, bitmap.config.argb_8888)

//canvas绘制的内容,将会在这个mbufferbitmap内

mbuffercanvas = canvas(mbufferbitmap)

}

}

然后在ontouchevent方面里面手指移动的时候,我们在缓存canvas里面进行绘制path:

motionevent.action_move -> { //手指移动的时候

//绘制圆滑曲线,即贝塞尔曲线,贝塞尔曲线这个知识自行了解

mpath.quadto(prex,prey,event.x,event.y)

//在缓存里面绘制

mbuffercanvas.drawpath(mpath,mpaint)

//重新绘制,会调用ondraw方法

invalidate()

prex = event.x

prey = event.y

}

然后ondraw的时候,就把缓存的canvas的bitmap当前view的canvas:

override fun ondraw(canvas: canvas) {

super.ondraw(canvas)

//画出缓存bitmap的内容

canvas.drawbitmap(mbufferbitmap,0f,0f,null)

}

就可以了,看看完整的代码100多行:

class tperaserview(context: context, attr: attributeset) : view(context,attr) {

companion object {

const val edit_mode_pen = 0x1l //画笔模式

const val edit_mode_eraser = 0x2l //橡皮擦模式

}

@retention(annotationretention.source)

@intdef(edit_mode_pen, edit_mode_eraser)

annotation class editmode

//当前编辑模式默认为画笔模式

@editmode

private var mmode: long = edit_mode_pen

private var prex: float = 0.0f //上一次的触摸点x坐标

private var prey: float = 0.0f //上一次触摸点y坐标

private var mpath = path() //path路径

//画笔

private var mpaint = paint(paint.anti_alias_flag or paint.dither_flag)

//想要绘制的内容先绘制到这个增加的canvas对应的bitmap上,

// 写完后再把这个bitmap的argb信息一次提交给上下文的canvas去绘制

private lateinit var mbufferbitmap: bitmap

private lateinit var mbuffercanvas: canvas

init {

mpaint.style = paint.style.stroke //画笔为实心

mpaint.color = color.red //颜色

mpaint.strokecap = paint.cap.round //笔触为圆形

mpaint.strokewidth = 10f //画笔大小

}

override fun onmeasure(widthmeasurespec: int, heightmeasurespec: int){

super.onmeasure(widthmeasurespec, heightmeasurespec)

mbufferbitmap = bitmap.createbitmap(measuredwidth, measuredheight, bitmap.config.argb_8888)

//canvas绘制的内容,将会在这个mbufferbitmap内

mbuffercanvas = canvas(mbufferbitmap)

}

override fun ondraw(canvas: canvas) {

super.ondraw(canvas)

//画出缓存bitmap的内容

canvas.drawbitmap(mbufferbitmap,0f,0f,null)

}

override fun ontouchevent(event: motionevent): boolean {

when(event.action){

motionevent.action_down -> { //手指按下的时候

//将起始点移动到当前坐标

mpath.moveto(event.x,event.y)

//记录上次触摸的坐标,注意action_down方法只会执行一次

prex = event.x

prey = event.y

}

motionevent.action_move -> { //手指移动的时候

//绘制圆滑曲线,即贝塞尔曲线,贝塞尔曲线这个知识自行了解

mpath.quadto(prex,prey,event.x,event.y)

//在缓存里面绘制

mbuffercanvas.drawpath(mpath,mpaint)

//重新绘制,会调用ondraw方法

invalidate()

prex = event.x

prey = event.y

}

motionevent.action_up ->{

//清除路径的内容

mpath.reset()

}

}

// true:告诉系统,这个触摸事件由我来处理

// false:告诉系统,这个触摸事件我不处理,这时系统会把触摸事件传递给imageview的父节点

return true

}

/**

* 设置画笔模式

*/

fun setmodel(@editmode model:long){

mmode = model

when(model){

edit_mode_pen -> {

mpaint.xfermode = null

}

edit_mode_eraser ->{

mpaint.xfermode = porterduffxfermode(porterduff.mode.clear)

}

}

}

}

三、清空画布实现

添加一个方法,按照上面的套路,把缓存canvas绘制清除即可。

/**

* 清空画布

*/

fun clear() {

mbuffercanvas.drawcolor(0, porterduff.mode.clear)

invalidate()

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持萬仟网。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值