麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 系統(tǒng) > Android > 正文

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

2019-10-21 21:32:38
字體:
供稿:網(wǎng)友

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

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

Android,畫板,橡皮擦

一、Xfermode

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

  • AvoidXfermode
  • PixelXorXfermode
  • PorterDuffXfermode

前面兩個(gè)因?yàn)椴恢С钟布铀僭贏PI 16已經(jīng)已經(jīng)過時(shí)棄用了。 簡單講一下第三個(gè)。

1.1 PorterDuffXfermode

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

Android,畫板,橡皮擦

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

二、實(shí)現(xiàn)

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

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 //當(dāng)前編輯模式默認(rèn)為畫筆模式 @EditMode private var mMode: Long = EDIT_MODE_PEN /**  * 設(shè)置畫筆模式  */ fun setModel(@EditMode model:Long){  mMode = model  when(model){   EDIT_MODE_PEN -> {    //畫線    mPaint.xfermode = null   }   EDIT_MODE_ERASER ->{    mPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)   }  } }

然后捋一下整個(gè)流程:

  • 畫筆模式,在onTouch時(shí)候畫出Path,繪制到view上
  • 然后切換到橡皮擦模式,畫出Path,clear擦掉原來的內(nèi)容
  • 再來回切換繪制

現(xiàn)在重點(diǎn)是解決第2點(diǎn),一個(gè)Path怎么做到不改變?cè)瓉淼膒ath基礎(chǔ)上換個(gè)繪制模式繼續(xù)畫呢?

如果你考慮第2點(diǎn)的話,效果是這樣子的:

What the fuck?(黑人問號(hào)) 這什么情況? 其實(shí)是因?yàn)閜ath只有一條,一直沒改變。所以,引入緩存Canvas和緩存Bitmap,添加兩個(gè)變量:

//想要繪制的內(nèi)容先繪制到這個(gè)增加的canvas對(duì)應(yīng)的bitmap上,// 寫完后再把這個(gè)bitmap的ARGB信息一次提交給上下文的canvas去繪制 private lateinit var mBufferBitmap: Bitmap private lateinit var mBufferCanvas: Canvas

然后在onMeasure中進(jìn)行初始化:

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) if(mBufferCanvas == null){   mBufferBitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)   //canvas繪制的內(nèi)容,將會(huì)在這個(gè)mBufferBitmap內(nèi)   mBufferCanvas = Canvas(mBufferBitmap)  }}

然后在onTouchEvent方面里面手指移動(dòng)的時(shí)候,我們?cè)诰彺鍯anvas里面進(jìn)行繪制path:

MotionEvent.ACTION_MOVE -> { //手指移動(dòng)的時(shí)候  //繪制圓滑曲線,即貝塞爾曲線,貝塞爾曲線這個(gè)知識(shí)自行了解  mPath.quadTo(preX,preY,event.x,event.y)  //在緩存里面繪制  mBufferCanvas.drawPath(mPath,mPaint)  //重新繪制,會(huì)調(diào)用onDraw方法  invalidate()  preX = event.x  preY = event.y}

然后onDraw的時(shí)候,就把緩存的Canvas的bitmap當(dāng)前view的Canvas:

override fun onDraw(canvas: Canvas) {  super.onDraw(canvas)  //畫出緩存bitmap的內(nèi)容  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 //當(dāng)前編輯模式默認(rèn)為畫筆模式 @EditMode private var mMode: Long = EDIT_MODE_PEN private var preX: Float = 0.0f //上一次的觸摸點(diǎn)x坐標(biāo) private var preY: Float = 0.0f //上一次觸摸點(diǎn)y坐標(biāo) private var mPath = Path() //path路徑 //畫筆 private var mPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG) //想要繪制的內(nèi)容先繪制到這個(gè)增加的canvas對(duì)應(yīng)的bitmap上, // 寫完后再把這個(gè)bitmap的ARGB信息一次提交給上下文的canvas去繪制 private lateinit var mBufferBitmap: Bitmap private lateinit var mBufferCanvas: Canvas init {  mPaint.style = Paint.Style.STROKE //畫筆為實(shí)心  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繪制的內(nèi)容,將會(huì)在這個(gè)mBufferBitmap內(nèi)  mBufferCanvas = Canvas(mBufferBitmap) } override fun onDraw(canvas: Canvas) {  super.onDraw(canvas)  //畫出緩存bitmap的內(nèi)容  canvas.drawBitmap(mBufferBitmap,0f,0f,null) } override fun onTouchEvent(event: MotionEvent): Boolean {  when(event.action){   MotionEvent.ACTION_DOWN -> { //手指按下的時(shí)候    //將起始點(diǎn)移動(dòng)到當(dāng)前坐標(biāo)    mPath.moveTo(event.x,event.y)    //記錄上次觸摸的坐標(biāo),注意ACTION_DOWN方法只會(huì)執(zhí)行一次    preX = event.x    preY = event.y   }   MotionEvent.ACTION_MOVE -> { //手指移動(dòng)的時(shí)候    //繪制圓滑曲線,即貝塞爾曲線,貝塞爾曲線這個(gè)知識(shí)自行了解    mPath.quadTo(preX,preY,event.x,event.y)    //在緩存里面繪制    mBufferCanvas.drawPath(mPath,mPaint)    //重新繪制,會(huì)調(diào)用onDraw方法    invalidate()    preX = event.x    preY = event.y   }   MotionEvent.ACTION_UP ->{    //清除路徑的內(nèi)容    mPath.reset()   }  }  // true:告訴系統(tǒng),這個(gè)觸摸事件由我來處理  // false:告訴系統(tǒng),這個(gè)觸摸事件我不處理,這時(shí)系統(tǒng)會(huì)把觸摸事件傳遞給imageview的父節(jié)點(diǎn)  return true } /**  * 設(shè)置畫筆模式  */ fun setModel(@EditMode model:Long){  mMode = model  when(model){   EDIT_MODE_PEN -> {    mPaint.xfermode = null   }   EDIT_MODE_ERASER ->{    mPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)   }  } }}

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

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

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

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到Android開發(fā)頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 黄色的视频免费看 | 成人福利在线免费观看 | 国产午夜亚洲精品午夜鲁丝片 | 好吊一区二区三区 | 天堂成人国产精品一区 | 国产一级aaa全黄毛片 | 久久色在线 | 一级一级一级毛片 | 日本黄色一级毛片 | 小雪奶水翁胀公吸小说最新章节 | 国产一区二区三区撒尿在线 | 国产精品视频在线观看免费 | 欧美成人高清视频 | 高清国产在线 | 国产一级爱c视频 | 成年人网站视频免费 | 久久草草影视免费网 | 色综合视频网 | 欧美性受ⅹ╳╳╳黑人a性爽 | 蜜桃久久一区二区三区 | 日韩欧美激情视频 | 男女一边摸一边做羞羞视频免费 | 婷婷久久影院 | www.99热视频 | 欧美成人免费一级 | 99爱福利视频在线观看 | 成年性羞羞视频免费观看 | av电影在线观看免费 | 91精品国产91热久久久做人人 | 黄色网址进入 | 欧美亚洲国产一区二区三区 | 精品国产91一区二区三区 | 91av99| 亚洲成人高清在线观看 | 97精品视频在线观看 | 最新午夜综合福利视频 | 国产一区免费 | 久精品久久 | 久久毛片免费观看 | 精品中文字幕在线播放 | 亚洲天堂中文字幕在线观看 |