MPAndroidChart自定義圖表Chart的Attribute及Render繪制邏輯
MPAndroidChart自定義圖表
聲明:本文MPChart 代表的就是 MPAndroidChart。
1. 自定義Chart的Attribute
我們回憶一下自定義View的過程里,通常我們會將一些屬性控制Attribute通過自定義View的構(gòu)造方法傳入,然后繪制或者layout的情況下使用這些屬性。Attribute類中的屬性,通過讀取attr.xml 中自定義的 View的 declare-styleable,在xml layoutInflate 時加載賦值給Attribute類。而MPChart的圖表同樣也是View,通過傳入Attribute屬性進行自定義相關(guān)的繪制,工欲善其事必先利其器。
例如,我們自定義一個CustomChart 繼承自BarChart,傳入CustomBarChartAttr 包含自定義的一些屬性控制變量的集合類, 類似圖1.0將一些公共的屬性放入BaseChartAttrs里。
圖1.0 自定義屬性Attribute
通過屬性控制,可以將我們自定義的一些差異性的數(shù)據(jù),需要用戶設(shè)定的比如顏色,大小、圓角的半徑等暴露出來;對于共性的屬性比如坐標(biāo)相關(guān)的,四個坐標(biāo),只顯示Bottom的XAxis,跟右邊的YAxis, 就可以直接在自定義的BarChart中寫死,工程需求不雷同于MPChart這種庫的提供者,他們需要考慮的是各色用戶的各種需求,所以需要考慮到API的全面性,而我們需要做的是盡量抽取共性到一個公共的類里,然后需求里的可變因素,減少出錯的幾率,將差異性的東西通過這里比如Attribute去設(shè)定,或者后續(xù)還會提到在Entry里包含屬性,Entry能夠具體到Chart里某一個item的屬性,而Attribute 一般只能控制到Chart, 或者這些Item的共有屬性上。
2. Render 自定義繪制邏輯
上篇文章里我們介紹了Chart的繪制,分別由負責(zé)各個小部件的Render去繪制,當(dāng)自定義的需求只是需改局部比如圖表的主體的時候,而XAxis、YAxis、邊框等的繪制不用改變,則只要替換負責(zé)主體繪制的Render對象,例如MPChart原本庫里的Chart里有一個負責(zé)繪制圖表的主體的DataRenderer mRenderer; 這里只需替換該Render對象,將自定義的繪制邏輯加在自定義的Render里。
@Override protected void init() { super.init(); mRenderer = new CustomBarChartRenderer(this, mAnimator, mViewPortHandler); }
這里自定義的是BarChart類型,因此CustomBarChartRenderer 繼承自BarChartRenderer, 這樣可以免去很多BarChart中原本的繪制,而只需關(guān)注需求所要的改動。
當(dāng)拿到Renderer之后,我們可以隨心所欲地去繪制各種需求,比如如下繪制帶小紅花的7天的柱狀圖:
圖1.1 flowerBarChart
從上篇文章里我們了解到BarChart的繪制會在drawDataSet()方法里,涉及到繪制矩形位置的信息存儲在BarBuffer里,然后通過Transformer轉(zhuǎn)為RectF的坐標(biāo)點,這里有7個矩形,所以Buffer里存儲有 4 * 7 = 28個值的數(shù)組,每次取四個值組成RectF, 然后就在RectF里繪制背景,繪制Bitmap、繪制各色各樣的需求都Okay。
圖1.2 FlowerBarChart 的繪制。
3. DataBuffer
接下來我們看一個實際的生產(chǎn)環(huán)境里的一種圖表的繪制,涉及到需要處理 Buffer 數(shù)據(jù)的存儲轉(zhuǎn)化。我們先看IPhone的 蘋果健康的一個數(shù)據(jù)圖表:
圖1.3 蘋果健康心率圖表
MPChart內(nèi)目測是沒有這種類型圖表的,那么拿到這個我們該如何做呢?首先分析圖形中每個Item可能會有若干個小圓角矩形組成,如示例圖中綠色框里有三個小矩形組成,原來的BarBuffer數(shù)組4個值對應(yīng)一個RectF在這里不在適用了,筆者這里提供的一種解決方案如下:每個Entry還是對應(yīng)一個Item,這里自定義了一種SegmentEntry繼承自BarEntry,SegmentEntry 里包含了若干矩形繪制對應(yīng)的數(shù)據(jù)model, SegmentRectModel, 因為同屬于一個Item,這些同屬于Item的小矩形都有相同的XAxis坐標(biāo)屬性,所以SegmentRectModel 里只需保存YAxis對應(yīng)所需的信息。
public class SegmentRectModel { public float topValue; public float bottomValue; public int rectColor = -1; public int boardColor = -1; public int boardWidth = 0;//dp } open class SegmentBarEntry : RecyclerBarEntry { @JvmField var rectValueModelList: MutableList<SegmentRectModel>? = null private var segmentRange = 0 // 每種業(yè)務(wù)數(shù)據(jù)的segmentRange不一樣,心率、血氧、血壓等。 var maxValue = 0 var minValue = 0 }
SegmentBarEntry內(nèi)部存有 List 小矩形對應(yīng)的業(yè)務(wù)數(shù)據(jù)。
這里簡單介紹一下如何生成這一些列的小區(qū)間SegmentRectModel[bottom, top] , 以心率值為例。比如這一天下來穿戴設(shè)備產(chǎn)生了一下的心率值:
【45, 46, 48, 49, 52, 67, 69, 70, 75, 78, 90, 93, 94, 97, 99, 103, 158, 164, 169, 170】
這里引入一個參數(shù)用來將這些散點數(shù)據(jù)歸并成 數(shù)區(qū)間,Segment_range??赡懿煌N類的數(shù)據(jù),這個值不同,比如血氧 segment_range_spo 跟心率的 segment_range_hrm 取值不一樣,假如這里的segment_range_hrm取值5,那么上面的心率值計算后得到的區(qū)間列表為:
【[45, 52], [67,78], [90, 103], [158], [164,170]】這里有個單點值,可以寫成[158, 158], 由此對應(yīng)成SegmentRectModel的 bottom, top 值, 單點在小矩形中退化成為一個小圓點。
這些SegmentEntry 最總已集合的形式存入到DataSet中,然后計算生成Buffer數(shù)據(jù),這里的Buffer計算方式改變,所以專程定義一個類用來包含這種SegmentEntry的數(shù)據(jù)轉(zhuǎn)化邏輯。
//將DataSet中的SegmentEntry 的List<SegmentRectModel>的size累加給到Buffer private int computeBufferSize(IBarDataSet dataSet){ int rectListSizeSum = 0; int entryCount = dataSet.getEntryCount(); for (int i = 0; i < entryCount; i++) { BarEntry entry = dataSet.getEntryForIndex(i); if (entry instanceof SegmentBarEntry) { SegmentBarEntry segmentBarEntry = (SegmentBarEntry) entry; List<SegmentRectModel> rectList = segmentBarEntry.rectValueModelList; rectListSizeSum += rectList.size(); } } return rectListSizeSum; } int bufferSize = computeBufferSize(set) * 4;//乘以4 表示矩形。 mBarBuffers[i] = new SegmentBarChartBuffer(bufferSize, barData.getDataSetCount(), set.isStacked());
在自定義的SegmentBarChartBuffer的feed() 內(nèi)計算并保存SegmentEntry 中的系列小矩形經(jīng)過Transformer轉(zhuǎn)化前的數(shù)據(jù)。
圖1.4 SegmentBarChartBuffer
轉(zhuǎn)化成Buffer 內(nèi)的數(shù)據(jù)后,至此交給Transformer,最后會生成一系列的小矩形,同一Item Entry下面的RectF擁有相同的X軸坐標(biāo)值,繪制的Render也不再考慮這些差異性,從Buffer數(shù)組的0號index開始取,每次取4個繪制RectF,需要注意的是當(dāng)bottom - top 值小于 width時,可能退化成一條線。需要將它處理成一個圓點。
圖1.5 SegmentChart的繪制
至此,整個SegmentChart的繪制講解完了,比較完整的一個流程,涉及到圖表的整體屬性Attribute定義,Item Entry根據(jù)需求自定義,然后自定義Buffer數(shù)據(jù)的feed方式,最終交給Render去繪制的邏輯。最后看一下繪制的效果圖。
圖1.6 MPChart自定義心率圖表
以上就是MPAndroidChart自定義圖表Chart的Attribute及Render繪制邏輯的詳細內(nèi)容,更多關(guān)于MPAndroidChart自定義圖表的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android開發(fā)筆記之如何正確獲取WebView的網(wǎng)頁Title
獲取h5頁面的攜帶的title中是很簡單的,下面這篇文章主要給大家介紹了關(guān)于Android開發(fā)筆記之如何正確獲取WebView的網(wǎng)頁Title的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友們下面來一起看看吧2018-09-09Caused by: android.os.NetworkOnMainThreadException錯誤解決辦法
這篇文章主要介紹了Caused by: android.os.NetworkOnMainThreadException錯誤解決辦法,本文提供了2種解決方法,需要的朋友可以參考下2014-07-07Android中Rxjava實現(xiàn)三級緩存的兩種方式
這篇文章主要介紹了Android中Rxjava實現(xiàn)三級緩存的兩種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-04-04Android ViewPager實現(xiàn)圖片輪播效果
這篇文章主要為大家詳細介紹了Android ViewPager實現(xiàn)圖片輪播效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09