Android自定義有限制區(qū)域圖例角度自識(shí)別涂鴉工具類(lèi)
自定義View分為繼承自View和ViewGroup,繼承ViewGroup相比繼承View
- 在事件分發(fā)上ViewGroup多dispatchTouchEvent(事件分發(fā))和onInterceptTouchEvent(事件攔截)兩個(gè)方法
- 在繼承上ViewGroup需要著重處理onmeasure(測(cè)量)與onLayout(控制位置等),而繼承View重點(diǎn)在于onDrow(繪制)上
這篇我們就簡(jiǎn)單實(shí)現(xiàn)一個(gè)自定義簽名類(lèi),通過(guò)手指觸摸屏幕移動(dòng),顯示手指滑過(guò)的路徑。首先創(chuàng)建SignatureView并繼承自View:
class SignatureView constructor(context: Context?, attrs: AttributeSet? = null) :
View(context, attrs, 0) {
private lateinit var paint: Paint
private var mWidth = 0 //父類(lèi)寬度
private var mHeight = 0//父類(lèi)高度
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
mWidth = MeasureSpec.getSize(widthMeasureSpec)
mHeight = MeasureSpec.getSize(heightMeasureSpec)
paint = Paint()
//設(shè)置抗鋸齒
paint.isAntiAlias = true
//設(shè)置簽名筆畫(huà)樣式
paint.style = Paint.Style.STROKE
setMeasuredDimension(mWidth, mHeight)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
......
}
}
接下來(lái)需要做的其實(shí)就只有觸摸事件處理和繪制路徑兩個(gè)任務(wù)了。繪制需要在onDraw中通過(guò)咱們初始化的畫(huà)筆paint和canvas完成,那么觸摸事件則需要重寫(xiě)onTouchEvent方法監(jiān)聽(tīng):
override fun onTouchEvent(event: MotionEvent): Boolean {
super.onTouchEvent(event)
}
這里需要注意,由于簽名是實(shí)時(shí)記錄的,所以我們需要記錄下滑動(dòng)的點(diǎn),將其連接成一條線,再通過(guò)pain畫(huà)線。畫(huà)的過(guò)程是按下移動(dòng)的操作,所以在ACTION_MOVE的過(guò)程我們需要實(shí)時(shí)畫(huà)線。畫(huà)筆完成是抬起的動(dòng)作,所以在ACTION_UP時(shí)我們需要將之前的所有點(diǎn)繪制在畫(huà)布上。這里通過(guò)一個(gè)點(diǎn)的集合收集手指移動(dòng)的點(diǎn),用戶(hù)畫(huà)筆繪制。
//收集用戶(hù)繪制的點(diǎn)
private var allPoints: MutableList<Point> = ArrayList()
val p = Point(event.x.toInt(), event.y.toInt())
when (event.action) {
MotionEvent.ACTION_DOWN -> {
//用戶(hù)按下,表示重新開(kāi)始保存點(diǎn)
allPoints.clear()
allPoints.add(p)
}
MotionEvent.ACTION_UP -> {
postInvalidate() //重繪圖像
}
MotionEvent.ACTION_MOVE -> {
allPoints.add(p)
postInvalidate() //子線程可刷新
}
}
接下來(lái)就是在onDrow()中繪制,通過(guò)canvas.drawLine:
val first = allPoints[0] //第一個(gè)點(diǎn) val last = allPoints[allPoints.size-1] //最后一個(gè)點(diǎn) canvas.drawLine(first.x.toFloat(),first.y.toFloat(),last.x.toFloat(),last.y.toFloat(),paint)
到這里基本就結(jié)束了,但我們還需要撤回和清除的功能。這時(shí)候就需要想一想了,如果按照按下—>移動(dòng)—>抬起為一筆,那么撤回的話就需要將這個(gè)過(guò)程的所有點(diǎn)都清除。此時(shí)我們就可以將這個(gè)過(guò)程想象成一條線,在按下時(shí)記錄線的開(kāi)始,抬起記錄線的結(jié)束,再將這條線存放在一個(gè)集合中,如果需要撤回就將這條數(shù)據(jù)刪除。
//用于畫(huà)完圖后的顯示,在抬起時(shí),添加來(lái)自于allPoints的所有點(diǎn)的數(shù)據(jù)
private var allList: MutableList<List<Point>> = ArrayList()
//用于劃線過(guò)程中的顯示,當(dāng)集合allList存儲(chǔ)后,清空本集合中所有數(shù)據(jù)
private var allPoints: MutableList<Point> = ArrayList()
override fun onTouchEvent(event: MotionEvent): Boolean {
super.onTouchEvent(event)
val p = Point(event.x.toInt(), event.y.toInt())
when (event.action) {
MotionEvent.ACTION_DOWN -> {
//用戶(hù)按下,表示重新開(kāi)始保存點(diǎn)
allPoints = ArrayList()
allPoints.add(p)
}
MotionEvent.ACTION_UP -> {
//用戶(hù)松開(kāi)
allList.add(allPoints)
allPoints = ArrayList() //添加集合后,清除子集合
postInvalidate() //重繪圖像
}
MotionEvent.ACTION_MOVE -> {
allPoints.add(p)
postInvalidate() //子線程可刷新
}
}
return true
}
//上一步(清除本次繪畫(huà))
fun clearLatestData() {
if (allList.size > 0) {
allList.removeAt(allList.size - 1)
paints.removeAt(paints.size - 1)
}
postInvalidate()
}
清除就更簡(jiǎn)單了,直接清空集合中的所有線條即可,但一定不要忘記刷新視圖:
//重置(清除所有繪畫(huà))
fun clearAllData() {
allList.clear()
postInvalidate()
}
總結(jié)
其實(shí)整套下來(lái)說(shuō)難也不難,主要涉及的就是繼承自View方式的自定義View。由易而難,先實(shí)現(xiàn)最基礎(chǔ)的功能,通過(guò)觸摸事件的不同動(dòng)作采集我們需要的數(shù)據(jù),再配合onDrow方法繪制出采集的線條,一定不要忘記刷新視圖。撤回或者說(shuō)多顏色,多樣式的線條其實(shí)都是可以通過(guò)容器收集線條,針對(duì)不同的線條設(shè)置畫(huà)筆(paint)屬性達(dá)到需求的。這篇就講到這里希望對(duì)大家有所幫助,下篇咱們講講異形區(qū)域限制畫(huà)筆區(qū)域問(wèn)題。
以上就是Android自定義有限制區(qū)域圖例角度自識(shí)別涂鴉工具類(lèi)的詳細(xì)內(nèi)容,更多關(guān)于Android限制區(qū)域涂鴉工具類(lèi)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android中實(shí)現(xiàn)開(kāi)機(jī)自動(dòng)啟動(dòng)服務(wù)(service)實(shí)例
這篇文章主要介紹了Android中實(shí)現(xiàn)自動(dòng)啟動(dòng)服務(wù)實(shí)例,并開(kāi)機(jī)自動(dòng)啟用(無(wú)activity),的朋友可以參考下2014-06-06
android 多點(diǎn)觸摸圖片縮放的具體實(shí)現(xiàn)方法
2013-06-06
Android Studio 新手入門(mén)教程(一)基本設(shè)置圖解
這篇文章主要介紹了Android Studio 新手入門(mén)教程(一)基本設(shè)置圖解,需要的朋友可以參考下2017-12-12
Android編程實(shí)現(xiàn)動(dòng)態(tài)支持多語(yǔ)言的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)動(dòng)態(tài)支持多語(yǔ)言的方法,涉及Android資源、控件及屬性相關(guān)操作技巧,需要的朋友可以參考下2017-06-06
Android FlowLayout流式布局實(shí)現(xiàn)詳解
這篇文章主要為大家詳細(xì)介紹了Android FlowLayout流式布局的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
Android自定義View實(shí)現(xiàn)體重表盤(pán)詳解流程
對(duì)于安卓程序員來(lái)說(shuō),自定義view簡(jiǎn)直不要太重要,畢竟有很多功能,譬如圓形頭像這些,用單純的原生非常難以實(shí)現(xiàn),而用自定義view,簡(jiǎn)直分分鐘2021-11-11
Kotlin?Dispatchers協(xié)程調(diào)度器源碼深入分析
Kotlin協(xié)程不是什么空中閣樓,Kotlin源代碼會(huì)被編譯成class字節(jié)碼文件,最終會(huì)運(yùn)行到虛擬機(jī)中。所以從本質(zhì)上講,Kotlin和Java是類(lèi)似的,都是可以編譯產(chǎn)生class的語(yǔ)言,但最終還是會(huì)受到虛擬機(jī)的限制,它們的代碼最終會(huì)在虛擬機(jī)上的某個(gè)線程上被執(zhí)行2022-11-11
詳解Android獲取所有依賴(lài)庫(kù)的幾種方式
本篇文章主要介紹了詳解Android獲取所有依賴(lài)庫(kù)的幾種方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Flutter?Widget?之FocusableActionDetector使用詳解
這篇文章主要為大家介紹了Flutter?Widget?之FocusableActionDetector使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11

