MPAndroid框架入門
- ----知其形,方知其意*
Tips:
本文使用的MPAndroid版本:3.0.1
文內(nèi)不會(huì)有太多的API介紹,更多的是對(duì)MPAndroid圖表繪制的理解,希望能幫助到大家
本文主要內(nèi)容:
1,圖表的組成分析
2,MPAndroid中折線圖的組成
3,MPAndroid關(guān)鍵簡(jiǎn)介
一.圖表的組成分析
如果某天拿到一個(gè)需求,搞一個(gè)收益走勢(shì)圖,大概長(zhǎng)這個(gè)鬼樣子:
(圖比較丑,來自百度,將就一下)
第一眼看上去什么感覺?
是這樣:一臉懵逼,這線怎么畫的,這標(biāo)注位置又是怎么確定的?
還是這樣:這玩意簡(jiǎn)單得很,canvas.draw兩下就出來.
于是打開AS,搞一個(gè)自定義View,吧啦吧啦吧開敲
最后大概是這樣:
public void onDarw(Canvas canvas) {
super.onDraw(canvas);
drawHorizontalGrids(canvas);
drawVerticalLabels(canvas);
drawVerticalGrids(canvas);
drawHorizontalLeftLabels(canvas);
drawLeftChartLine(canvas);
}
(瞎編的代碼,只是個(gè)栗子)
最后這個(gè)View里,各種邏輯交錯(cuò),定義一大堆控制變量,各種計(jì)算參數(shù),以至于代碼臃腫(血淚教訓(xùn)),分分鐘趕超View.Java的節(jié)奏.
不管你是哪種情況,咱們都來分析一波這個(gè)圖上,到底都有些啥
第一步:分解看得到的元素
先不管這類圖有多復(fù)雜,由顯示內(nèi)容大致都可以分為這四個(gè)部分:
1,左側(cè)Y軸:左側(cè)數(shù)值標(biāo)注,左側(cè)軸線
2,折線(也可以看做是數(shù)據(jù)點(diǎn)的鏈接)
3,X軸:日期標(biāo)注(或其它的標(biāo)識(shí)),X軸軸線
4,右側(cè)Y軸:右側(cè)數(shù)值標(biāo)注,右側(cè)軸線
小結(jié):看得到的元素,其實(shí)就這么多.先別急著搞.接下來分析一下哪些真正影響圖表的,看不見的要素.
第二步:分解看不到的元素:
1,每一個(gè)點(diǎn)對(duì)象的構(gòu)成:由X軸坐標(biāo)+Y軸標(biāo)注決定其位置,點(diǎn)之間的連接構(gòu)成整條線段.
2,Y軸(左右):基于Y軸依賴的每像素單位,即每像素所占據(jù)的數(shù)值單位比,為什么說是基于Y軸依賴,從上面的圖表,我們可以看出,這兩條不同的走勢(shì)線,所對(duì)應(yīng)的Y軸標(biāo)注也是不一樣的,由此可知,左右兩側(cè)Y軸所對(duì)應(yīng)的具體數(shù)值比例,一般也可以看做Y max value不同.
3,X軸:基于X軸展示的每單位像素,兩點(diǎn),第一,為什么叫X軸所展示的,一般而言,我們拿到數(shù)據(jù)之后,會(huì)選擇直接把所有Data繪制到圖表上,也就是X軸總單位長(zhǎng)度(不是View的總長(zhǎng)度)為Data的長(zhǎng)度.但是如果這個(gè)圖表是可以左右滑動(dòng)的呢,這時(shí)候所展示的就可能是Data的一段位置,例如從下標(biāo)為20的數(shù)據(jù)到80的數(shù)據(jù).第二,為什么叫每單位像素,因?yàn)樵赬軸上,我們可能要繪制的內(nèi)容會(huì)跟每一個(gè)數(shù)據(jù)點(diǎn)對(duì)象有關(guān),側(cè)重點(diǎn)在于對(duì)象上故而這樣稱呼(另外還有單位粒度,就不在這里多做解釋了).
4,Draw Boundary Constraint:繪制范圍約束:
這里的Draw Boundary Constraint(以下簡(jiǎn)稱為DBC)類似,但是不同于一個(gè)View的寬高約束.為什么需要單獨(dú)再抽出一個(gè)DBC,因?yàn)樗粌H僅是對(duì)數(shù)據(jù)繪制范圍的約束,更進(jìn)一步而言,它也是各個(gè)組件之間聯(lián)結(jié)的中心點(diǎn).通過這樣一個(gè)DBC的定義,也可以讓我們的代碼更清晰簡(jiǎn)潔.不至于到后期為了增加一個(gè)偏移量offset之類的就把代碼搞亂.
小結(jié):
基于以上幾點(diǎn)的簡(jiǎn)單分析.我們可以大概得到一張這樣的結(jié)構(gòu)圖:
二.MPAndroid中折線圖的組成(LineChart)
為什么之前要畫那么多篇幅向各位介紹圖表的組件概念,因?yàn)檫@樣理一遍思路,方便我們能進(jìn)一步理解Philjay大神在MPAndroid中的一些設(shè)計(jì),類似的構(gòu)思也可以在其它類庫(kù)中得到體現(xiàn),比如lecho的HelloChart,也是一個(gè)比較出名的Android圖表庫(kù).
2.1 LineChart的參與繪制的主要成員.
LineChart,折線圖,從哪開始看?自然是從自定義控件三大核心方法:onMeasure(),onLayout(),onDraw()走起.在LineChart的直接繼承類中,onLayout()(對(duì)子View進(jìn)行了Layout);onMeasure()(僅做了一個(gè)最小高度的約束50dp).里面代碼不多,這里就不做詳細(xì)分析了.
重點(diǎn)部分在onDraw()方法中(基類Chart邏輯比較簡(jiǎn)單,這里主要介紹的是BarLineChartBase.java中的onDraw()).
// execute all drawing commands
drawGridBackground(canvas);
if (mAutoScaleMinMaxEnabled) {
autoScale();
}
if (mAxisLeft.isEnabled())
mAxisRendererLeft.computeAxis(mAxisLeft.mAxisMinimum, mAxisLeft.mAxisMaximum, mAxisLeft.isInverted());
if (mAxisRight.isEnabled())
mAxisRendererRight.computeAxis(mAxisRight.mAxisMinimum, mAxisRight.mAxisMaximum, mAxisRight.isInverted());
if (mXAxis.isEnabled())
mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false);
mXAxisRenderer.renderAxisLine(canvas);
mAxisRendererLeft.renderAxisLine(canvas);
mAxisRendererRight.renderAxisLine(canvas);
mXAxisRenderer.renderGridLines(canvas);
mAxisRendererLeft.renderGridLines(canvas);
mAxisRendererRight.renderGridLines(canvas);
if (mXAxis.isEnabled() && mXAxis.isDrawLimitLinesBehindDataEnabled())
mXAxisRenderer.renderLimitLines(canvas);
if (mAxisLeft.isEnabled() && mAxisLeft.isDrawLimitLinesBehindDataEnabled())
mAxisRendererLeft.renderLimitLines(canvas);
if (mAxisRight.isEnabled() && mAxisRight.isDrawLimitLinesBehindDataEnabled())
mAxisRendererRight.renderLimitLines(canvas);
// make sure the data cannot be drawn outside the content-rect
int clipRestoreCount = canvas.save();
canvas.clipRect(mViewPortHandler.getContentRect());
mRenderer.drawData(canvas);
// if highlighting is enabled
if (valuesToHighlight())
mRenderer.drawHighlighted(canvas, mIndicesToHighlight);
// Removes clipping rectangle
canvas.restoreToCount(clipRestoreCount);
mRenderer.drawExtras(canvas);
if (mXAxis.isEnabled() && !mXAxis.isDrawLimitLinesBehindDataEnabled())
mXAxisRenderer.renderLimitLines(canvas);
if (mAxisLeft.isEnabled() && !mAxisLeft.isDrawLimitLinesBehindDataEnabled())
mAxisRendererLeft.renderLimitLines(canvas);
if (mAxisRight.isEnabled() && !mAxisRight.isDrawLimitLinesBehindDataEnabled())
mAxisRendererRight.renderLimitLines(canvas);
mXAxisRenderer.renderAxisLabels(canvas);
mAxisRendererLeft.renderAxisLabels(canvas);
mAxisRendererRight.renderAxisLabels(canvas);
if (isClipValuesToContentEnabled()) {
clipRestoreCount = canvas.save();
canvas.clipRect(mViewPortHandler.getContentRect());
mRenderer.drawValues(canvas);
canvas.restoreToCount(clipRestoreCount);
} else {
mRenderer.drawValues(canvas);
}
mLegendRenderer.renderLegend(canvas);
drawDescription(canvas);
drawMarkers(canvas);
可以看到,在onDraw里面,作者把整個(gè)圖表的繪制大致拆成了很多子模塊,View(Chart extend View)本身處理的主要就是一些公共方法,例如自動(dòng)縮放,canvas 旋轉(zhuǎn),背景繪制等.組件之間的關(guān)系大致如下:
軸:
Axis負(fù)責(zé)對(duì)該軸的行為進(jìn)行約束管理,例如軸線,限制線,標(biāo)注等.
Renderer負(fù)責(zé)具體繪制行為,同時(shí)從Axis中拿到對(duì)應(yīng)信息
Chart提供Canvas,DBS.詢問Axis是否需要進(jìn)行繪制.
Data:
DataRender:數(shù)據(jù)繪制,Axis就是Chart本身.
Legend: LegendRender:Legend繪制,無(wú)具體Axis.
其它:
description,markers,Log等等
這里簡(jiǎn)單整理了一下大致流程圖:
對(duì)了,作者本身提供了一個(gè)Log來統(tǒng)計(jì)圖表的繪制時(shí)間,在項(xiàng)目中如果要調(diào)試這一部分的性能,是可以把這個(gè)Log打開的
3.一些關(guān)鍵類的介紹
3.1 ViewPortHandler
這玩意,就是我在上面說的DBC了.
先來看看作者的描述:
*Class that contains information about the charts current viewport settings, including offsets, scale & translation** L**evels,*
這個(gè)類包含了一些關(guān)于視圖的信息和設(shè)置,有offsert(偏移量),scale(縮放比),translation(位移信息)等.
由此可知,通過ViewPortHandler,我們可以得到這個(gè)圖表很多重要信息,例如圖表的寬高(同樣也有初始化時(shí)機(jī)問題,否則會(huì)為0),縮放比(縮放也是通過該類進(jìn)行實(shí)現(xiàn)的),偏移量(這玩意終于有一個(gè)比較好的解決方案了,以往在自定義View中很容易玩脫)等.
3.2 Axis(軸信息封裝類)
對(duì)應(yīng)Chart(餅圖,雷達(dá)圖除外)中X,Y軸,每一個(gè)軸都有自己的封裝.值得注意的是,要區(qū)分XAxis和YAxis.
Axis軸中,主要封裝的信息:
ValueFormatter軸格式化器,會(huì)將對(duì)應(yīng)軸上的點(diǎn)傳遞下來,用于展示軸上的標(biāo)注信息,如X軸可以看做是傳遞的數(shù)據(jù)索引值,可以用來從原始數(shù)據(jù)中獲取到時(shí)間,或者其它相關(guān)信息.Y軸獲取的是數(shù)值信息,可以用來做單位格式化信息等.
Color,Width,軸線寬度,顏色.繪制與否等.
Entry:Label的數(shù)量,是否繪制等.
Space最小單位間隔(讓每個(gè)數(shù)據(jù)點(diǎn)之間的距離更寬闊,或更密集)
AxisMaxNum(最大值,同樣的,還有最小值,不設(shè)置就是數(shù)據(jù)的最大最小值,同樣也可以自定義最大最小值)
Tips:可以通過一些設(shè)置來讓標(biāo)簽不重疊,不超出邊界.
3.3 Renderer渲染器
Tips:如果需要自定義,記得把Chart的Axis,Renderer,Transformer傳遞下去,否則會(huì)出現(xiàn)各種數(shù)據(jù)繪制不統(tǒng)一的問題.
主要是根據(jù)Axis的信息,在Chart需要的時(shí)候進(jìn)行內(nèi)容繪制.
喜聞樂見的canvas.drawXXX()
由于篇幅問題,這里不對(duì)Chart的繪制多做分析了,MPAndroid的繪制可以說是一個(gè)非常細(xì)致的過程,作者在對(duì)數(shù)據(jù)的處理(Buffer等),對(duì)象的回收(MPPoint),縮放;等方面做了很多努力.下次如果有時(shí)間,再單獨(dú)寫一篇關(guān)于它在繪制中,對(duì)數(shù)據(jù)處理這些方面的分析
以上,能閱讀到這里,十分感謝,希望本文有幫到你.
....看在編輯文本搞了半個(gè)多小時(shí)的情況下,不點(diǎn)個(gè)贊再走?