Android画板开发(二) 橡皮擦实现
Android画板开发(一) 基本画笔的实现
Android画板开发(二) 橡皮擦实现
Android画板开发(三) 撤销反撤销功能实现
Android画板开发(四) 添加背景和保存画板内容为图片
Android画板开发(五) 添加文本文字
在上一篇实现了简单的画板功能, 这篇实现橡皮擦功能,首先分析一下应该如何实现:
在Andriod有个图像混合(Xfermode)概念,利用这个概念我们就可以实现橡皮擦功能。
一、Xfermode
Paint有一个方法setXfermode(Xfermode)
,这个方法设置图像的混合模式。参数有三个子类:
- AvoidXfermode
- PixelXorXfermode
- PorterDuffXfermode
前面两个因为不支持硬件加速在API 16已经已经过时弃用了。 简单讲一下第三个。
1.1 PorterDuffXfermode
该类有且只有一个含参的构造方法PorterDuffXfermode(PorterDuff.Mode mode),参数就是设置图像的混合模式,下面这张图片形象地说明了各种模式的作用
我们的做橡皮擦的时候,就是用到了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//当前编辑模式默认为画笔模式@EditModeprivate var mMode: Long = EDIT_MODE_PEN/*** 设置画笔模式*/fun setModel(@EditMode model:Long){mMode = modelwhen(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: Bitmapprivate 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.xpreY = 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//当前编辑模式默认为画笔模式@EditModeprivate var mMode: Long = EDIT_MODE_PENprivate 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: Bitmapprivate lateinit var mBufferCanvas: Canvasinit {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.xpreY = event.y}MotionEvent.ACTION_MOVE -> { //手指移动的时候//绘制圆滑曲线,即贝塞尔曲线,贝塞尔曲线这个知识自行了解mPath.quadTo(preX,preY,event.x,event.y)//在缓存里面绘制mBufferCanvas.drawPath(mPath,mPaint)//重新绘制,会调用onDraw方法invalidate()preX = event.xpreY = event.y}MotionEvent.ACTION_UP ->{//清除路径的内容mPath.reset()}}// true:告诉系统,这个触摸事件由我来处理// false:告诉系统,这个触摸事件我不处理,这时系统会把触摸事件传递给imageview的父节点return true}/*** 设置画笔模式*/fun setModel(@EditMode model:Long){mMode = modelwhen(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()}
Android画板开发(二) 橡皮擦实现相关推荐
- Android画板开发(四) 添加背景和保存画板内容为图片
Android画板开发(一) 基本画笔的实现 Android画板开发(二) 橡皮擦实现 Android画板开发(三) 撤销反撤销功能实现 Android画板开发(四) 添加背景和保存画板内容为图片 A ...
- Android画板开发(一) 基本画笔的实现
Android画板开发(一) 基本画笔的实现 Android画板开发(二) 橡皮擦实现 Android画板开发(三) 撤销反撤销功能实现 Android画板开发(四) 添加背景和保存画板内容为图片 A ...
- 【Android游戏开发二十七】讲解游戏开发与项目下的hdpi 、mdpi与ldpi资源文件夹以及游戏高清版本的设置...
今天一个开发者问到我为什么游戏开发要删除项目下的hdpi.mdpi和ldpi文件夹:下面详细给大家解答一下: 首先童鞋们如果看过我写的<[Android游戏开发二十一]Android os设备谎 ...
- Android 蓝牙开发(二) --手机与蓝牙音箱配对,并播放音频
Android 蓝牙开发(一) – 传统蓝牙聊天室 Android 蓝牙开发(三) – 低功耗蓝牙开发 项目工程BluetoothDemo 上一章中,我们已经学习了传统蓝牙的开发,这一章,我们来学习如 ...
- 【Android游戏开发二十二】(图文详解)游戏中灵活实现动画播放!简述J2me的游戏类库与Android游戏开发!
本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi ) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/andr ...
- CSDN Android客户端开发(二):详解如何基于Java用Jsoup爬虫HTML数据
本文参考鸿洋大大的链接详细介绍如何使用Jsoup包抓取HTML数据,是一个纯java工程,并将其打包成jar包.希望了解如何用java语言爬虫网页的可以看下. 杂家前文就又介绍用HTTP访问百度主页得 ...
- 【Android游戏开发二十三】自定义ListView【通用】适配器并实现监听控件!
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/374.html L ...
- 【Android游戏开发二十五】在Android上的使用《贝赛尔曲线》!
首先对于<赛贝尔曲线>不是很了解的童鞋,请自觉白度百科.google等等... 为了方便偷懒的童鞋,这里给个<贝赛尔曲线>百科地址,以及一段话简述<贝赛尔曲线>: ...
- Android添加拍照功能,Android相机开发(二): 给相机加上偏好设置
Android Camera Develop: add settings to camera app 概述 继上一篇实现了一个最简单的相机APP后,本篇主要介绍实现相机的各种偏好设置,比如分辨率.闪光 ...
最新文章
- JavaScript 的使用简单总结
- 汽车的燃油清洁剂有什么用处?
- WD强势出击 推出全球业界首款2TB硬盘
- css餐厅_餐厅的评分预测
- LeetCode 563二叉树的坡度-简单
- BugkuCTF-MISC题啊哒,白哥的鸽子
- 三天学好ADO(转)
- ProtoBuf3语法指南(Protocol Buffers)_下
- 学习ARM的一些基本知识,个人整理
- excel服务器2010网站,勤哲Excel服务器2010企业版(完整安装包)
- 基于libmodbus库实现modbus TCP/RTU通信
- 【网络安全基础】数字签名原理及应用
- C语言float去尾法输出,c语言去尾法怎么写
- 威刚SU600固态硬盘不识别通电无反应慧荣SM系列主控数据恢复![图]
- 杂感-ThinkPad E570
- 2019年架构软考论文押题(二)
- 基于大数据的软件项目知识图谱构造及问答方法
- 调试 GPS 1.575G干扰无法搜星问题
- 西安电子科技大学计算机专硕调剂,西安电子科技大学人工智能学院2020研究生调剂通知...
- [ZZ]Windows磁盘驱动基础教程