前言
?????? 最近項(xiàng)目中新增了一個(gè)搶購模塊,需要一個(gè)進(jìn)度指示條,UI設(shè)計(jì)了幾款出來后,PM一看,不行,太low了,沒有逼格 balabala... 后來看到了淘寶的淘搶購模塊,眼前一亮,好 就它了。
????? 吶,就長這樣:
?????? 當(dāng)時(shí)看到這張圖的時(shí)候,其實(shí)我。。。我是拒絕的。甚至還有點(diǎn)想打人。。。
?????? 不過為了世界和平,還是要給PM點(diǎn)贊。
?????? 吐槽歸吐槽,需求還是要做的(廣大程序員的勞苦心聲。。。)
? ? ? 一番努力過后,終于擼出來了(沒毛病),先給大家看一下實(shí)現(xiàn)的最終效果:
好了,接下來就一步一步實(shí)現(xiàn)該效果。
效果實(shí)現(xiàn)
?一. 背景實(shí)現(xiàn)
? ? ? 分析:背景邊框是一個(gè)圓角矩形,用 canvas.drawRoundRect? 就可以實(shí)現(xiàn),背景這里我采用的是一張圖片,轉(zhuǎn)化為Bitmap類型,然后用? canvas.drawBitmap? 繪制出來。
1.繼承View,重寫構(gòu)造方法以及初始化Paint:
2.重寫onSizeChanged? onDraw方法:
??? 這里的背景框比較好實(shí)現(xiàn):?
???? 需要注意的一點(diǎn)是, drawRoundRect? 還要其他類似的重載方法:
?????? 條紋背景就稍微麻煩一點(diǎn)了。本來我想著是不是可以通過循環(huán)? drawRectF?? 出每一個(gè)小條紋,后來想著太麻煩了,就讓UI幫我做了一張圓角條紋圖,然后直接? drawBitmap? 進(jìn)去。
????????? 但是這樣做有個(gè)弊端,就是如果UI做的圖不是剛好圓角的話,那么左右兩邊的圖片會(huì)溢出圓角矩形一點(diǎn),效果不好,類似這樣:
? ? ? ? 無奈之下,只好使用大殺器? PorterDuffXfermode, 圖形混合模式,這里還是借用一張經(jīng)典的圖吧,相信大家都看過了:
?????? 一般的寫法就是這樣:
? ????? 什么意思呢,給大家解釋一下:先建立兩個(gè)概念
? ? ? ? 當(dāng)給 Paint 設(shè)置了不同模式的? PorterDuffXfermode 后,dst? 與? src 發(fā)生部分重疊或者其他情況時(shí)(一般都是用于部分重疊),那么 dst? 與? src? 就會(huì)按照對應(yīng)的混合模式進(jìn)行顯示。就比如 SRC_IN? 模式,對照上文提到的經(jīng)典圖,圓形和矩形發(fā)生重疊的部分是一個(gè)扇形,圓形是? dst ,矩形是? src, 那么按照? SRC_IN 模式,重疊的? src? 部分進(jìn)行保留,其他的部分就不顯示了,這樣就完成了圖形混合。?
??????? 在這里只能簡單的解釋一下了,太深入的話感覺這個(gè)進(jìn)度條完不成了啊 (太深入我也不會(huì)了 〒▽〒) ,只要這里理解了,那么本文的自定義view也就完成一半了。
??????? 好了,接下來就是正式的開始繪制背景圖了。
????? a). 先創(chuàng)建一個(gè)空的 bitmap 裝載在一個(gè)新的畫布上,然后在畫布上繪制一個(gè) 圓角矩形,以不遮擋之前繪制好的背景邊框?yàn)闇?zhǔn)。
????? b). 然后為 paint 設(shè)置 SRC_IN 的圖形混合模式,再在該畫布上把我們做好的條紋圖繪制進(jìn)來,這樣,之前繪制的圓角矩形就做為? dst ,后來繪制的條紋圖就做為 src 。
????? c). 這樣,重疊的部分始終是圓角矩形范圍,而且 條紋圖 會(huì)把這個(gè) 圓角矩形填充滿(因?yàn)樵诶L制條紋圖時(shí)設(shè)置的 dstRectF 和圓角矩形一致)。
????? d). 根據(jù)? SRC_IN 的規(guī)則,條紋圖與圓角矩形重疊的部分保留,溢出的部分則不予顯示,這樣的話,就算 UI 給的圖不是剛好圓角,也是可以滿足需求的。
還有一點(diǎn)需要注意的事,給 Paint? 設(shè)置混合模式,繪制完后,如果還要繪制其他東西,則取消混合模式,即? setXfermode( null )。
????? 背景終于繪制出來了:
二. 進(jìn)度條實(shí)現(xiàn)
?????? 分析:其實(shí)繪制進(jìn)度條和繪制背景圖原理一樣,只是換了一張和背景紋理一樣但是顏色不同的圖片,還有一點(diǎn)就是,進(jìn)度條的寬度需要根據(jù)比例來進(jìn)行調(diào)整,那么就在為 進(jìn)度條繪制 dst 圓角矩形的時(shí)候,根據(jù)比例設(shè)置該圓角矩形的寬度就行了啊。
???????????? 這里我就直接上代碼了:
?????????? 可以看到,和繪制 背景 的時(shí)候原理相同,唯一不同的是,做為 dst 的圓角矩形在繪制時(shí),寬度會(huì)根據(jù)比例進(jìn)行調(diào)整。
?????????? 做為? src? 的進(jìn)度圖片在繪制的時(shí)候,繪制的區(qū)域還是整個(gè) View 的圓角矩形區(qū)域,這樣可以保證 進(jìn)度條圖片不會(huì)變形。
?????????? 還有一點(diǎn)需要注意的是,進(jìn)度條圖片 與 背景圖片 紋理最好保持一致,這樣實(shí)現(xiàn)的效果才比較美觀,不然分分鐘逼死強(qiáng)迫癥。
三. 文字實(shí)現(xiàn)
還有最后一個(gè)部分,就是文字信息繪制。
??????? 分析:文字繪制這一塊,其實(shí)難度不大,就是用?? drawText? 進(jìn)行繪制,控制好繪制的起點(diǎn)坐標(biāo),然后根據(jù)售出比例調(diào)整即可。唯一的難點(diǎn)就在于文字的變色,當(dāng)進(jìn)度條覆蓋在文字上時(shí),要顯示出白色的文字。
??????? 其實(shí)這個(gè)想一下是不是可以用我們之前畫進(jìn)度條的思路來解決:
??????? 1. 先把紅色的文字全部繪制出來。
??????? 2. 然后繪制一個(gè)跟隨進(jìn)度變化的白色圓角矩形區(qū)域。
??????? 3. 那么該白色圓角矩形區(qū)域與文字的重疊部分,不就是文字線條部分嗎?(想象一下蓋章的時(shí)候,白紙就是我們的白色圓角矩形,章上面的字就是我們的文字,只不過章上面的字是突起的,蓋章的時(shí)候不就是章上突起的字與白紙接觸的地方被染上印泥了嗎。)
??????? 4.上面一條理解了,再來分析我們的實(shí)現(xiàn)思路,當(dāng)白色圓角矩形區(qū)域與文字重疊的時(shí)候,把重疊區(qū)域染成白色,不就成了白色的文字了嗎。
??????? 5.用代碼實(shí)現(xiàn)就是 :把 白色圓角矩形當(dāng)做? src ,之前寫好的紅色文字為? dst ,采用? SRC_IN? 的圖形混合模式,顯示出重疊部分的? src 就可以實(shí)現(xiàn)該效果了。
好了,上代碼:
?????????? 這里再提一點(diǎn)就是,繪制 text 的時(shí)候,起始點(diǎn)的坐標(biāo)就是文字左下角 的 基準(zhǔn)點(diǎn),而不是左上角,至于基準(zhǔn)點(diǎn)的 Y
坐標(biāo),一般的計(jì)算方法就是:
?????????? 如果需要?jiǎng)赢嬓Ч脑挘ň褪窃O(shè)置了固定進(jìn)度后,進(jìn)度條會(huì)一點(diǎn)一點(diǎn)走過去,而不是瞬間完成),這里只需要另外設(shè)置一個(gè)新的變量代替 當(dāng)前進(jìn)度,而且讓該新變量從0自增至當(dāng)前進(jìn)度大小,自增過程中讓 View 重繪就可以了。
總結(jié)
? ? ? 好了,這一個(gè)自定義? View? 已經(jīng)被我們完成了(其實(shí)還有很多其他的方案,我一開始是想繼承? ProgressBar,但是思路上大都差不多,有興趣的可以自己動(dòng)手實(shí)現(xiàn)一下哈),大家可以發(fā)現(xiàn),乍看一下感覺很難很復(fù)雜的 View,在拆分成一個(gè)個(gè)小模塊后,問題也就迎刃而解了,所以嘛,不要感覺 自定義 View 是一個(gè)很難的東西,Google? 已經(jīng)為我們封裝了一套很完善的 api ,剩下的就靠我們的想象力了。
寫在最后
????? 本人剛開始寫博客,文筆生疏,排版不佳,有些地方表述的不太清楚,個(gè)人的理解也有不全面的地方,望各位看官輕噴。有任何的意見或者建議歡迎給我留言。
? ? ? 項(xiàng)目我已經(jīng)上傳到 github 了,有興趣的可以去看一下,順手一個(gè) Star? 也是極好的 ●_●
????? Github 地址:https://github.com/zhlucky/SaleProgressView?