Android画板开发之橡皮擦功能

发布时间:2019-08-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Android画板开发之橡皮擦功能脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

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

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

Android画板开发之橡皮擦功能

一、Xfermode

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

  • AvoidXfermode
  • PixelXorXfermode
  • PorterDuffXfermode

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

1.1 PorterDuffXfermode

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

Android画板开发之橡皮擦功能

我们的做橡皮擦的时候,就是用到了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()  }
android教程
脚本网站
android studio

脚本宝典总结

以上是脚本宝典为你收集整理的Android画板开发之橡皮擦功能全部内容,希望文章能够帮你解决Android画板开发之橡皮擦功能所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: