自定義View---鎖屏控件

本篇文章已授權(quán)微信公眾號(hào) guolin_blog (郭霖)獨(dú)家發(fā)布

最近學(xué)習(xí)了一些自定義控件的知識(shí),想著趁熱多做些練習(xí)來鞏固,上周自定義了一個(gè)等級(jí)進(jìn)度條,是一個(gè)自定義View,這周就換一個(gè)類型,做一個(gè)自定義的ViewGroup。這周自定義ViewGroup的是一個(gè)鎖屏控件,效果如下:



效果分析:

仔細(xì)分析效果圖發(fā)現(xiàn),鎖屏控件需要繪制的有三個(gè)部分,分別是:

1.圖案點(diǎn),圖案點(diǎn)有四種狀態(tài),分別是默認(rèn)、選中、正確和錯(cuò)誤

2.圖案點(diǎn)之間的連線

連線會(huì)根據(jù)1中點(diǎn)的狀態(tài)改變發(fā)生顏色上的變化

3.懸空線段

就是圖案點(diǎn)和懸空點(diǎn)之間的線段



整體思路:

1.自定義一個(gè)LockScreenView來表示圖案點(diǎn),LockScreenView有四種狀態(tài)

2.自定義一個(gè)LockScreenViewGroup,在onMeasure中獲取到寬度以后(根據(jù)寬度算圖案點(diǎn)之間的間距),動(dòng)態(tài)地將LockScreenView添加進(jìn)來

3.在LockScreenViewGroup的onTouchEvent中消耗觸摸事件,根據(jù)觸摸點(diǎn)的軌跡來更新LockScreenView、圖案點(diǎn)連線和懸空線段



實(shí)現(xiàn):

1.自定義LockScreenView

由于沒有和這個(gè)自定義View比較類似的原生控件,因此自定義的時(shí)候直接繼承自View


首先,需要的屬性通過構(gòu)造函數(shù)傳入:


View的狀態(tài)用一個(gè)枚舉類型來表示:

View的狀態(tài)通過暴露一個(gè)方法給LockScreenViewGroup來進(jìn)行設(shè)置。


在onDraw方法中判斷類型,進(jìn)行繪制:

這里在選中時(shí)用屬性動(dòng)畫做了一個(gè)放大效果,在下次恢復(fù)正常的時(shí)候要將大小恢復(fù)回去:


在LockScreenViewGroup中,我將LockScreenView的寬高設(shè)置為wrap_content,因此需要在onMeasure方法做一些特殊的處理,至于為什么要做特殊處理,在上一篇博文《等級(jí)進(jìn)度條》中已經(jīng)提到過了。



2.自定義LockScreenViewGroup

為了方便確定子View的位置,LockScreenViewGroup繼承自RelativeLayout

在xml中賦予了如下屬性:

其中itemCount表示一行有幾個(gè)LockScreenView,其它屬性都已經(jīng)提到過了


在構(gòu)造函數(shù)中解析xml中的自定義屬性:


在onMeasure方法中,獲取到LockScreenViewGroup的寬以后,算出LockScreenView之間的間隙,并動(dòng)態(tài)地將LockScreenView添加進(jìn)來(每個(gè)LockScreenView添加進(jìn)來的時(shí)候,設(shè)置id作為唯一標(biāo)識(shí),后面在判斷圖案是否正確時(shí)會(huì)用到):

這里有兩個(gè)地方需要注意一下:

1.LockScreenView的寬不能用getMeasuredWidth方法來獲取,因?yàn)檫@里只是把LockScreenView創(chuàng)建了出來,還沒有對(duì)它進(jìn)行測(cè)量,故通過getMeasuredWidth方法只能得到0,這里直接把LockScreenView中大圓的直徑當(dāng)作它的寬(因?yàn)檫@里動(dòng)態(tài)添加的時(shí)候用了wrap_content, 并且沒有設(shè)padding)

2.重寫onMeasure方法的時(shí)候不能把super.onMeasure方法刪掉,因?yàn)檫@里面會(huì)進(jìn)行子View寬高的測(cè)量,刪了子View就畫不出來了


觸摸事件的消耗在onTouchEvent中處理(在這個(gè)案例中也可以在dispatchTouchEvent方法中處理,因?yàn)樽覸iew的狀態(tài)由LockScreenViewGroup告訴它了,子View不需要處理觸摸事件)。

在onTouchEvent方法中對(duì)Down、Move、Up三種不同的觸摸狀態(tài)分別做了處理。

(1)首先,在Down狀態(tài)時(shí),需要對(duì)之前的狀態(tài)做一些重置:

其中,mCurrentViews用來保存當(dāng)前選中的LockScreenView的id,mCurrentPath用來保存圖像點(diǎn)間線段的路徑,skyStartX、skyStartY分別是懸空線段起始的x和y。

(2)在Move狀態(tài)時(shí),判斷是否在LockScreenView區(qū)域,如果在某個(gè)LockScreenView區(qū)域且這個(gè)LockScreenView之前沒有被選中,則將這個(gè)LockScreenView設(shè)置為選中狀態(tài)。另外在onMove中還做了圖案點(diǎn)間線段路徑和懸空線段起點(diǎn)和終點(diǎn)(mTempX、mTempY)的更新,懸空線段的起點(diǎn)就是上一個(gè)被選中的LockScreenView的中心點(diǎn)。

(3)在Up狀態(tài)時(shí),根據(jù)答案的正確與否,對(duì)LockScreenView設(shè)置不同的狀態(tài),并且對(duì)懸空線段起始點(diǎn)進(jìn)行重置

在onTouchEvent方法最后會(huì)調(diào)用invalidate方法對(duì)視圖進(jìn)行重繪,這時(shí)會(huì)調(diào)用dispatchDraw方法進(jìn)行子View的繪制。


在dispatchDraw方法中進(jìn)行圖像點(diǎn)間的線段路徑以及懸空線段的繪制:

這里要注意,在重寫dispatchDraw方法時(shí),不能把super.dispatchDraw方法刪掉,因?yàn)檫@里會(huì)繪制LockScreenViewGroup的子View(即,LockScreenView們),如果刪了,動(dòng)態(tài)添加的LockScreenView就會(huì)顯示不出來(重寫的時(shí)候不小心刪了,排查好久才發(fā)現(xiàn)是這里的問題,都是淚orz)


最后附上github源碼地址:LockScreenVIew

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,057評(píng)論 25 709
  • 君子之交淡如水 1.在人生的客車上你會(huì)遇到各種形形色色的人,有些人來過你的世界又匆匆的走了,這些人你可能來不及打...
    簡(jiǎn)兮先生閱讀 359評(píng)論 0 0
  • 親愛的Me: 這是寫給你第38封信。為了讓娃早餐多吃點(diǎn),一直以來你都想著花樣的做早餐,突然感覺到整齊和色彩就會(huì)讓人...
    一黍花園閱讀 205評(píng)論 0 1
  • 【0913今日剽悍】An 1、有些事情必須自己經(jīng)歷現(xiàn)場(chǎng)才有意義。比如作家的親筆簽名版的書,去不去現(xiàn)場(chǎng)感覺完全不同。...
    An_An閱讀 113評(píng)論 0 0
  • #從零開始學(xué)習(xí)寫作#19大學(xué)里學(xué)PPT不會(huì)后悔的三個(gè)理由! 臨近畢業(yè)季,好多人開始廣投簡(jiǎn)歷,經(jīng)常會(huì)寫上一項(xiàng)“熟練運(yùn)...
    歡仔熊閱讀 981評(píng)論 0 2

友情鏈接更多精彩內(nèi)容