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

一、分析

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

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

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

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

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

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

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

二、实现

如何实现撤回功能

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类来保存每笔的 画笔和路径,然后撤销时候重新绘制。

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

(0)

相关推荐

  • Android画板开发之橡皮擦功能

    在上一篇实现了简单的画板功能, 这篇实现橡皮擦功能,首先分析一下应该如何实现, 在Andriod有个图像混合(Xfermode)概念,利用这个概念我们就可以实现橡皮擦功能. 一.Xfermode Paint有一个方法setXfermode(Xfermode),这个方法设置图像的混合模式.参数有三个子类: AvoidXfermode PixelXorXfermode PorterDuffXfermode 前面两个因为不支持硬件加速在API 16已经已经过时弃用了. 简单讲一下第三个. 1.1 Po

  • Android自定义SurfaceView实现画板功能

    接触了这么久的View,总不能一直停留在View里,现在开始呢,就要学习一个新的知识点:SurfaceView,实际上SurfaceView与View的原理都差不多,只是效率和渲染方式上,SurfaceView要优于View,这也是我们写这个的原因.今天就看看这个SurfaceView,好了,下面就是今天要说的效果. 界面很简单,就是一个按钮以及一个画板,先看看界面的代码吧 <LinearLayout xmlns:android="http://schemas.android.com/ap

  • android实现简单的画画板实例代码

    直接看代码,注释都写清楚了 复制代码 代码如下: public class MainActivity extends Activity { private ImageView iv; private Bitmap baseBitmap; private Canvas canvas; private Paint paint; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedIns

  • Android采用双缓冲技术实现画板

    本文实例为大家分享了Android实现画板的具体代码,采用的技术是双缓冲技术,供大家参考,具体内容如下 1.双缓冲技术的概念 所谓的双缓冲技术其实很简单,当程序需要在指定的View上进行绘制时,程序并不需要直接绘制到该View组件,而是先绘制到一个内存中的Bitmap图片上(就是缓冲),等内存中的Bitmap绘制好之后,再一次性将Bitmap绘制到View组件上. 2.Android采用双缓冲实现画板  实现的思路: 1).定义一个内存中图片,将他作为缓冲区Bitmap cacheBitmap

  • Android实现画画板案例

    本文实例为大家分享了Android实现画画板的具体代码,供大家参考,具体内容如下 ① 准备一个布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools&q

  • Android画板开发之添加背景和保存画板内容为图片

    一.绘制背景 绘制背景的方法有两种: 自己利用canvas进行绘制 利用view的自带方法进行绘制 1.1 canvas绘制背景 自己绘制的背景的方法就是在onDraw回调进行绘制的时候,先draw一个背景,再进行draw原来的内容 override fun onDraw(canvas: Canvas) { super.onDraw(canvas) //先绘制颜色作为背景 canvas.drawColor(Color.BLACK) //画出缓存bitmap的内容 canvas.drawBitma

  • Android画板开发之添加文本文字

    一.前言 添加文本,也是属于 一个比较简单的功能,在第二篇的时候,添加了橡皮擦,在橡皮擦里面通过一个模式的形式进行画笔的判断,当然文本也是如此,添加一个文本模式,在onTouchDown的时候,弹出PopupWindow,输入文本,然后PopupWindow消失的时候,利用staticLayout绘制到画布上即可.当然也有些需要注意的地方 下面一步步来实现 二.实现 2.1 添加文本模式 例如橡皮擦那样,添加多一个文本模式,然后setModel的时候,需要把画笔的样式修改为FILL,如果是STR

  • Android画板开发之基本画笔功能

    一.简介 这是画板系列的第一篇,一步步开始,从简单的画板,到功能稍微齐全一点的画板,例如基本画笔.橡皮擦.背景.文字.撤销.反撤销.保存等 这篇带大家实现一个最简单的画板,前提是需要对自定义View有一定的了解. 用的是kotlin语言 二.实现 分析如何实现: 定义了画笔和Path,然后在触摸屏幕的时候,手指一边移动一边进行path的滑动,绘制.这就完成了一个最简单的画笔功能. 下面几十行代码完成这个 class TPView(context: Context,attr:AttributeSe

  • 双缓冲技术实现Android 画板应用

    什么是双缓冲技术?双缓冲技术就是当用户操作界面完成后,会有一个缓冲区保存用户操作的结果. 为什么要使用双缓冲技术?拿Android 游戏开发来说,界面贞每次都是全部重画的,也就说画了新的,旧的就没了,所以需要使用双缓冲技术保存之前的内容. 如何实现双缓冲?使用一个Bitmap对象保留之前的画布即可. package com.example.phonegaptest; import android.content.Context; import android.graphics.Bitmap; i

  • Android多媒体之画画板开发案例分享

    先看看效果: 其实画画板的原理很简单,就是首先记录下按下屏幕的点,然后每移动一下就让这两次移动的点连线,周而复始,图像就由很多条直线构成了. 核心代码 : public class MainActivity extends Activity implements OnClickListener,OnSeekBarChangeListener { private View red_view,green_view,blue_view; //控制画笔颜色的三块区域 private SeekBar se

随机推荐