软件编程
位置:首页>> 软件编程>> Android编程>> Android画板开发之撤销反撤销功能

Android画板开发之撤销反撤销功能

作者:tpnet  发布时间:2023-11-28 10:08:37 

标签:Android,画板,撤销

一、分析

这篇将会讲解撤销反撤销功能的实现,先讨论一下这个原理是怎么样实现的。

每次撤回的内容,内容是怎么定义呢? 其实就是每一笔,每一笔作为撤回的内容,那每一笔怎么算呢,就是算手指从按下-移动-放开这一个过程就是一笔。

我们只需记录这个过程为一笔,然后用一个已画列表list列表来记录这个过程的paint画笔和路径path。

撤销的时候就把后面的一个数据移到另一个撤销列表

反撤销的时候,就把撤销列表的最后面那条数据移动到已画列表。

然后,还有一个重点,就是画笔的保存数量,上面说记录每一笔画笔,这当然是有个限度,不可能画了好几百笔都记录下来,这样子内存消耗很大的,所以超出显示画笔数量的时候,我们就把以前的画死在画板上。

Android画板开发之撤销反撤销功能

基本原理是这样子的。接下来跟着我实现

二、实现

如何实现撤回功能

2.1 定义数据类

首先,需要一个bean类存储每一笔的数据,这里定义一个PaintData,里面需要定义个draw方法,因为撤销的时候,需要重新绘制。


data class PaintData(
   var mPaint: Paint,  //保存画笔

var mPath: Path     //保存路径
) {
 /**
  * 撤销和反撤销之后 重新绘制
  * @param canvas 绘制的画布
  */
 fun draw(canvas: Canvas){
   canvas.drawPath(mPath,mPaint)
 }

}

2.2 修改清空画板方法

因为多了列表,所以清空画板的方法需要把列表也清除了


/**
  * 清空画布
  * @param isClearList 时候清空数据列表
*/
 fun clear(isClearList:Boolean) {
   if(isClearList){
     mRevokedList.clear()
     mPaintedList.clear()
   }
   mBufferCanvas.drawColor(0, PorterDuff.Mode.CLEAR)
   invalidate()
 }

2.3 实现撤销方法

在view定义两个列表,一个是已经画的内容列表,一个是撤销内容的列表


//储存已经写的笔画
private var mPaintedList: MutableList<PaintData> = ArrayList<PaintData>()

//已经撤销的列表
private var mRevokedList: MutableList<PaintData> = ArrayList<PaintData>()

添加固话层canvas和bitmap,超出记录的画笔就写死在固化层了


//固化层,超出最大笔画就先绘制到这个层
private lateinit var mHoldBitmap: Bitmap
private lateinit var mHoldCanvas: Canvas

//最多记录20画笔迹
private val MAX_PAINT_RECORED = 20

//在测量的时候进行初始化:
 override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
   if(mBufferCanvas == null){
     mBufferBitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)

//canvas绘制的内容,将会在这个mBufferBitmap内
     mBufferCanvas = Canvas(mBufferBitmap)
   }

if(mHoldCanvas == null){
     mHoldBitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)
     mHoldCanvas = Canvas(mHoldBitmap)
   }
 }

然后定义撤回的方法


/**
* 撤回一个笔迹
* @return 是否撤回成功
*/
 fun revoked(){
   reDraw(mPaintedList)
 }

反撤销方法基本一致,只是改了个列表:


/**
  * 反撤回一个笔迹
  */
 fun unRevoked(){
   reDraw(mRevokedList)
}

然后重新绘制的方法为:


/**
  * 重新绘制
  * @param paintList 需要操作的list
*/
 private fun reDraw(paintList:MutableList<PaintData>){

if(paintList.size > 0){
     val paint = paintList.removeAt(paintList.size-1)
     if(paintList === mPaintedList){
       mRevokedList.add(paint)
     }else{
       mPaintedList.add(paint)
     }

//清空缓存画板
     mBufferCanvas.drawColor(0, PorterDuff.Mode.CLEAR)

invalidate()

}
 }

然后就是画笔的保存,在触摸按下的时候,进行画笔的保存


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

//保存画笔
       mPaintedList.add(PaintData(Paint(mPaint),Path(mPath)))

}
     MotionEvent.ACTION_MOVE -> { //手指移动的时候

//绘制圆滑曲线,即贝塞尔曲线,贝塞尔曲线这个知识自行了解
       mPaintedList.get(mPaintedList.size-1).mPath.quadTo(preX,preY,event.x,event.y)

//重新绘制,会调用onDraw方法
       invalidate()

preX = event.x
       preY = event.y
     }
     MotionEvent.ACTION_UP ->{

//清除路径的内容
       mPath.reset()

}
   }

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

最后绘制的时候:


override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)

//超出缓存的就固化到缓存bitmap
   while(mPaintedList.size > MAX_PAINT_RECORED){
     val paintData = mPaintedList.removeAt(0)
     paintData.draw(mHoldCanvas)
   }

//绘制固化的内容到缓存Canvas
   mBufferCanvas.drawBitmap(mHoldBitmap,0f,0f,null)

//绘制记录的画笔
   for(paint in mPaintedList){
     //重新绘制每个path
     paint.draw(mBufferCanvas)
   }

//画出缓存bitmap的内容
   canvas.drawBitmap(mBufferBitmap,0f,0f,null)

}

最后清除画布的时候,需要把画笔列表也清除了:


/**
  * 清空画布
*/
 fun clear() {
   mRevokedList.clear()
   mPaintedList.clear()
   mHoldCanvas.drawColor(0, PorterDuff.Mode.CLEAR)
   mBufferCanvas.drawColor(0, PorterDuff.Mode.CLEAR)
   invalidate()

}

重点就是在于利用一个bean类来保存每笔的 画笔和路径,然后撤销时候重新绘制。

来源:https://blog.csdn.net/niubitianping/article/details/78408603

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com