自定義View——IndicatorView,源碼地址:ttdevs github
0x00 main
進步淘衙、創(chuàng)新都是在不斷變化的需求中誕生的。
-- By ttdevs
這不彤守,新的需求又來了。廢話不多說具垫,先上設計稿:
簡單分析上圖包括三部分:最上面的類Progressbar,中間兩個指示盤和最下面的指示盤卦碾。第一個類Progressbar我們項目之前有實現(xiàn)過,但是和這個需求有一些差異洲胖,因此決定重新實現(xiàn)一遍坯沪。另外兩個圓形指示盤本想通過在一張背景圖片上放一張指針圖绿映,控制指針圖的旋轉來實現(xiàn)腐晾,但是考慮到這樣不夠靈活,因此也決定自己來畫赴魁。So,我們接下來實現(xiàn)這三個View颖御。
正式開始之前,先看看我們最終效果圖(當然潘拱,指針是可以動的):
0x01 分析
-
LineIndicator (第一個芦岂,類Progressbar)
主要包括三部分:左側的提示和內容瘪弓,右側的提示和內容禽最,中間的類Progressbar腺怯。兩側的文字比較容易處理,掌握了文字的基本繪制呛占,畫起來是很容易的。中間的類Progressbar由于打算自己畫晾虑,所以不會直接貼個Progressbar在上面。我的思路是畫一條長的直線作為背景帜篇,中間的指示也是直線,比背景直線粗洪灯,直線的Paint設置
StrokeCap
為Paint.Cap.ROUND
即paint.setStrokeCap(Paint.Cap.ROUND);
,這樣就可以有兩頭半圓的效果逃沿;中間的指示數(shù)字直接畫在粗的指示直線上面即可婴渡。這里可能遇到的問題有下面兩個:-
StrokeCap
設置 為Paint.Cap.ROUND
時的位置關系StrokeCap
設置 為Paint.Cap.ROUND
幻锁,直線兩側的半圓是不算在直線的長度里的。簡單來說哄尔,如果view的長度和我畫的直線長度一致,那么這個直線就是矩形而不是期待的兩側都是半圓的橢圓岭接。 -
當進度為0或者為100%時的展示
如果我們背景直線和指示直線起點終點位置一致,那么最終效果就是當進度為0或者100%的時候鸣戴,指示直線是顯示不全的,因此我們需要對這兩個位置進行矯正创千。我的矯正方法比較簡單,在0~x和y~100%進度的時候分別顯示x和y(本以為自己的思路很屌追驴,后來發(fā)現(xiàn)別人也是這么干的)疏之。
-
-
CircleIndicator (中間的多種顏色環(huán))
這個View我將其分解為四部分,從上層到下層:中間指針锋爪,刻度環(huán)爸业,顯示的內容,圓環(huán)背景和外層指示文字沃呢。每一部分再做分解:
-
中間指針
這個又分解為六個部分:最下層大圓拆挥,兩個圓形半圓薄霜,兩個三角形和上層小圓纸兔。
-
刻度環(huán)
由于是圓環(huán),所以必須畫弧線了汉矿。但是這個弧線又有點特殊,兩側帶圓角奈揍,中間圓環(huán)直角,這個沒想到啥好辦法赋续,用了很一般的思路:先用
Paint.Cap.ROUND
畫兩側的弧,然后Paint.Style.STROKE
畫中間的部分纽乱。 -
顯示的內容
這個就比較簡單了,主要在于計算文字的顯示位置鸦列。
-
圓環(huán)背景和外層文字
最簡單的一個圓,加一個以圓為路徑畫的文字顽爹。
-
最后我們畫的順序正好與上面所述順序相反。
-
ProgressIndicator (最下面的兩種顏色環(huán))
這個相較 CircleIndicator 就簡單了一些镜粤。在畫圓環(huán)的時候诲锹,我們只需要先畫一個灰色背景,然后再畫一個綠色圓弧即可归园。
0x02 實現(xiàn)
View的繪制我們應該都比較熟悉,主要有下面三個過程: onMeasure(測量)庸诱、onLayout(布局)晤揣、onDraw(繪制)朱灿。針對上述三個View:LineIndicator,我們根據實際的內容來計算View的高度盗扒,寬度用戶設定;CircleIndicator和ProgressIndicator的寬度用戶設定侣灶,高度自定計算與寬度相同。onLayout我們不需要池户。最后的根據實際的展示內容來繪制凡怎。
另外校焦,由于CircleIndicator和ProgressIndicator和相似度高统倒,很多代碼可以拿來重用,因此檐薯,我寫了一個基類來完成公共的部分注暗,特殊部分每個 子類自己完成。最后再子類地onDraw方法中按照順序調用即可赚楚。
由于主要是計算各種坐標位置,代碼還是不少的宠页,這里就不貼代碼寇仓。最后的實現(xiàn)請移步我的 github。三個View的代碼已經整理完LineIndicator遍烦,其它的兩個還需要點時間(2016-06-19)。
0x03 知識點
-
自定義View的思路
- 創(chuàng)建類服猪,繼承自View或者ViewGroup或者其它ViewGroup
- 定義View的可配置參數(shù)拐云,如果你需要的話
- 實現(xiàn)View的具體邏輯
這個太粗略了近她,各位可以參考具體源碼。
-
文字位置的計算
如果你沒有自己畫過文字粘捎,那你肯定不可能一下子明白文字的畫法,或多或少的出現(xiàn)偏移捅暴。這里直接給大家推薦一篇講的非常詳細的文章:http://blog.csdn.net/aigestudio/article/details/41447349
-
位置、半徑蓬痒、弧長等的計算
這里會涉及到簡單的三角函數(shù)和圓的周長弧度的計算漆羔,可能要說的就是三角函數(shù)的參數(shù)是弧度制度。
-
ObjectAnimator
/** * 設置內容的顏色值(非resource的id) * * @param contentColor 內容的顏色值 * @param unitColor 單位的顏色值 */ public void setContentColor(int contentColor, int unitColor) { mContentColor = contentColor; mUnitColor = unitColor; } /** * 設置進度 * * @param indicator 進度值 */ public void setIndicator(float indicator) { if (indicator <= mStartIndicator) { mIndicator = mStartIndicator; } else if (indicator > mEndIndicator) { mIndicator = mEndIndicator; } else { mIndicator = indicator; } postInvalidate(); } /** * 獲取進度 * * @return 當前進度值 */ public float getIndicator() { return mStartIndicator; } public void animateIndicator(float indicator) { Interpolator interpolator = new AnticipateOvershootInterpolator(1.8f); ObjectAnimator animation = ObjectAnimator.ofFloat(this, "indicator", indicator); animation.setDuration(2000); animation.setInterpolator(interpolator); animation.start(); }
-
處理屏幕的旋轉
由于時間比較緊亲轨,這個我還沒做。主要在View的以下兩個方法中實現(xiàn):
@Override protected Parcelable onSaveInstanceState() { return super.onSaveInstanceState(); } @Override protected void onRestoreInstanceState(Parcelable state) { super.onRestoreInstanceState(state); }
最后歡迎各位吐槽并提供更好的建議~~