作者:rokudol,鏈接:
http://blog.rokudol.cn/%E8%87%AA%E5%AE%9A%E4%B9%89view---%E5%BC%BA%E5%A4%A7%E7%9A%84%E5%AF%86%E7%A0%81%E8%BE%93%E5%85%A5%E6%A1%86.html,本文由作者授權(quán)發(fā)布。
我司之前有個需求,要求類似支付寶那樣的密碼支付,產(chǎn)品要求輸入的當(dāng)前字符需要是明文密碼,1s后轉(zhuǎn)換為圓點(diǎn),原本想網(wǎng)上那么多密碼輸入框,肯定沒問題,結(jié)果UI一出圖就懵逼了,翻遍了各個角落,都找不到類似的密碼輸入框,沒辦法,自己寫吧。
使用方法,在gradle中添加:compile ‘com.rokudoll:PswText:1.0.0’即可使用
當(dāng)然繪制思路參照了其他大佬的思路,言歸正傳,先來看看效果圖:

1需求分析
拿到效果圖,再結(jié)合產(chǎn)品的要求,整理出以下要求:
1、類似EditText的password模式,輸入密碼時(shí),輸入的當(dāng)前密碼為明文,而之前的密碼變?yōu)閳A點(diǎn),1s后當(dāng)前密碼也變?yōu)閳A點(diǎn)
2、整體密碼框?yàn)橐粋€顏色,而已輸入或當(dāng)前輸入密碼位置的密碼框?yàn)榱硪粋€顏色
3、有陰影
2實(shí)現(xiàn)流程
自定義view的流程就不再贅述了,不太清楚的可以去看看鴻洋和郭林的教程,先寫好自定義屬性,按照之前分析的結(jié)果以及自己的一點(diǎn)想法,為了更方便的使用,就有了以下的自定義屬性,目前沒有使用枚舉,全部都是以boolean值來規(guī)定使用哪種模式,不過之后會換成枚舉,那么先來看看有哪些自定義屬性:

設(shè)置好自定義屬性后,就開始實(shí)現(xiàn)這個自定義控件了!首先肯定是計(jì)算寬高
onMeasure
作為一個數(shù)學(xué)很差的人,計(jì)算這個的過程確實(shí)是比較糟心的。。直接看圖吧

圖中說明兩處:
1、spacingWidth:為什么在寬度已知的情況下,spacingWidth = borderWidth / 4:
很簡單,因?yàn)橛眠吙虻膶挾瘸?得到的大小剛好是能讓我接受的大小,且在pswLength = 7、8、9、10的時(shí)候,寬度也比較合適,說白了就是一點(diǎn)點(diǎn)湊出來的。
2、borderWidth:為什么在寬度已知的情況下,borderWidth = (width?4) / ((5?pswLength) - 1),
這個其實(shí)很好理解,當(dāng)寬度已知的時(shí)候,borderWidth = width / 6 - spacingWidth,即寬度除以6減去一個間隙的寬度就等于一個邊框的寬度,而間隙的寬度 = borderWidth /4,那么我們換算成一個方程式來看看,就一目了然了,如果這個方程式還看不懂,那就去請教一下初中數(shù)學(xué)老師吧。。

來看看完整代碼:

按這種算法繪制出的view,其實(shí)右邊還多了一個spacingWidth的寬度,因?yàn)槲覀兘o每一個邊框都減去了一個spacingWidth的寬度,所以會多出一個spacingWidth的寬度,不過并不影響,我們可以在onDraw里把每一個密碼框往右移0.5個spacingWidth的寬度,這樣左右都空出了一小段空隙,視覺效果上也好看一點(diǎn),直接來看看onDraw。
onDraw
繪制pswLength數(shù)量個密碼框
先說說思路,我們用for循環(huán)的方式,循環(huán)繪制出pswLength個密碼框,用canvas.drawRoundRect繪制密碼框,如果使用圖片的話,就繪制圖片,那么來看看canvas.drawRoundRect需要傳遞的參數(shù):
drawRoundRect(RectF rect, float rx, float ry, Paint paint)
rect:RectF對象,邊框的具體坐標(biāo)
rx,ry:圓角x,y軸的半徑
paint:畫筆
那我們先來計(jì)算邊框的具體坐標(biāo),來看看草稿:

沒錯,這草稿就是這么low,數(shù)學(xué)差。。就是這么心酸,不過已經(jīng)可以看出規(guī)律,前面說過,我們是用for循環(huán)的方式循環(huán)繪制出各個密碼框,那么總結(jié)一下:
top = 0
bottom = height
left = i (borderWidth + spacingWidth)
right ?= borderWidth + i (borderWidth + spacingWidth)
? ? ? ?= ((i + 1) borderWidth) + (i spacingWidth)
這樣繪制出來的密碼框,就像前面提過的,右邊會多出一個spacingWidth,所以我們left和right的坐標(biāo)需要再改進(jìn)一下:
int left = (int) ( (i?(borderWidth + spacingWidth)) + (0.5?spacingWidth));
int right = (int) (((i + 1)?borderWidth) + (i?spacingWidth) + (0.7 * spacingWidth));
有同學(xué)要問了,為毛right要乘以0.7而不是0.5,因?yàn)槌艘?.5邊框位置還是不對呀!微調(diào)一下,乘以0.7剛剛好。
到這里并沒有結(jié)束,為啥?
因?yàn)檎f好的可以用圖片來繪制邊框,我們還沒有實(shí)現(xiàn)這一步,不過也很簡單,不需要重新計(jì)算坐標(biāo),直接貼該部分的完整代碼:

只繪制明文密碼模式
這個很簡單,就不多做解釋了

說明一點(diǎn),為什么在textX最后要加0.5*spacingWidth,因?yàn)槲覀兝L制密碼框的時(shí)候就多增加了這么多的寬度,所以繪制文字也要做同樣的操作,同理,繪制圓點(diǎn)時(shí)也是一樣,后面不多做贅述
只繪制圓點(diǎn)模式

繪制輸入密碼時(shí)密碼框變換樣式:

輸入密碼時(shí),輸入的當(dāng)前密碼為明文,1s后變?yōu)閳A點(diǎn)模式,即默認(rèn)模式

可能有同學(xué)注意到,這里我們計(jì)算的圓點(diǎn)坐標(biāo)跟之前計(jì)算的不一樣,為什么呢?因?yàn)樵谶@里,我們計(jì)算的圓點(diǎn)坐標(biāo)分為兩種情況:
1、輸入密碼時(shí),已輸入的密碼變?yōu)閳A點(diǎn),那么我們的圓點(diǎn)坐標(biāo)就應(yīng)該是用(i - 1)的方式去計(jì)算,這樣才能實(shí)現(xiàn)輸入到第二個密碼時(shí),第一個密碼變?yōu)閳A點(diǎn)
2、輸入密碼時(shí),延遲1s后當(dāng)前明文密碼變?yōu)閳A點(diǎn),那么圓點(diǎn)坐標(biāo)就應(yīng)該是(i + 1)的方式計(jì)算
延遲繪制圓點(diǎn)

以上就是全部的繪制邏輯,計(jì)算坐標(biāo)這類似乎沒什么好解釋的,接下來就是自定義鍵盤,界面不需要我們自己再重新設(shè)計(jì),用系統(tǒng)的就好,來看看代碼
鍵盤

說明一下只處理數(shù)字那部分,為什么是keyCode - 7,我們點(diǎn)進(jìn)源碼看看

可以看出,我們用keyCode - 7就剛好等于輸入的數(shù)字
最終效果:

3結(jié)語
以上就是該自定義view的全部說明,并未貼出全部的完整代碼,如有需要可到GitHub查看完整源碼,如果喜歡或覺得該控件對你有幫助還請點(diǎn)個star,文中如有錯誤還請指出,謝謝