Android畫板開發(fā)之橡皮擦功能

在上一篇實現(xiàn)了簡單的畫板功能, 這篇實現(xiàn)橡皮擦功能,首先分析一下應該如何實現(xiàn),

公司主營業(yè)務:做網(wǎng)站、成都網(wǎng)站設計、移動網(wǎng)站開發(fā)等業(yè)務。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)建站是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)建站推出高郵免費做網(wǎng)站回饋大家。

在Andriod有個圖像混合(Xfermode)概念,利用這個概念我們就可以實現(xiàn)橡皮擦功能。

Android畫板開發(fā)之橡皮擦功能

一、Xfermode

Paint有一個方法setXfermode(Xfermode),這個方法設置圖像的混合模式。參數(shù)有三個子類:

  • AvoidXfermode
  • PixelXorXfermode
  • PorterDuffXfermode

前面兩個因為不支持硬件加速在API 16已經(jīng)已經(jīng)過時棄用了。 簡單講一下第三個。

1.1 PorterDuffXfermode

該類有且只有一個含參的構造方法PorterDuffXfermode(PorterDuff.Mode mode),參數(shù)就是設置圖像的混合模式,下面這張圖片形象地說明了各種模式的作用

Android畫板開發(fā)之橡皮擦功能

我們的做橡皮擦的時候,就是用到了PorterDuff.Mode.CLEAR這個模式清除圖像,所以說橡皮擦也是Path,只是繪制的模式不一樣了。

二、實現(xiàn)

在上一篇的文章中,實現(xiàn)了最簡單筆畫畫板,就是只有一個畫筆模式,所以首先添加一個橡皮擦的繪制模式。

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擦掉原來的內容
  • 再來回切換繪制

現(xiàn)在重點是解決第2點,一個Path怎么做到不改變原來的path基礎上換個繪制模式繼續(xù)畫呢?

如果你考慮第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方法只會執(zhí)行一次
    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:告訴系統(tǒng),這個觸摸事件由我來處理
  // false:告訴系統(tǒng),這個觸摸事件我不處理,這時系統(tǒng)會把觸摸事件傳遞給imageview的父節(jié)點
  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)

   }
  }
 }

}

三、清空畫布實現(xiàn)

添加一個方法,按照上面的套路,把緩存canvas繪制清除即可。

 /**
  * 清空畫布
  */
 fun clear() {
  mBufferCanvas.drawColor(0, PorterDuff.Mode.CLEAR)
  invalidate()
 }

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

文章標題:Android畫板開發(fā)之橡皮擦功能
本文網(wǎng)址:http://bm7419.com/article34/jjesse.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供手機網(wǎng)站建設、網(wǎng)站維護自適應網(wǎng)站、外貿網(wǎng)站建設、小程序開發(fā)、電子商務

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運營