MPAndroid框架入門

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è)鬼樣子:

原圖.png

(圖比較丑,來自百度,將就一下)

第一眼看上去什么感覺?
是這樣:一臉懵逼,這線怎么畫的,這標(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è)圖上,到底都有些啥

第一步:分解看得到的元素

image

先不管這類圖有多復(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)圖:

image

二.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)系大致如下:

image

軸:

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)單整理了一下大致流程圖:

image

對(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è)贊再走?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市庇麦,隨后出現(xiàn)的幾起案子葱蝗,更是在濱河造成了極大的恐慌钦无,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拉盾,居然都是意外死亡靴患,警方通過查閱死者的電腦和手機(jī)仍侥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸳君,“玉大人农渊,你說我怎么就攤上這事』蚣眨” “怎么了砸紊?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)囱挑。 經(jīng)常有香客問我醉顽,道長(zhǎng),這世上最難降的妖魔是什么平挑? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任游添,我火速辦了婚禮,結(jié)果婚禮上弹惦,老公的妹妹穿的比我還像新娘否淤。我一直安慰自己,他們只是感情好棠隐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布石抡。 她就那樣靜靜地躺著,像睡著了一般助泽。 火紅的嫁衣襯著肌膚如雪啰扛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天嗡贺,我揣著相機(jī)與錄音隐解,去河邊找鬼。 笑死诫睬,一個(gè)胖子當(dāng)著我的面吹牛煞茫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼续徽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蚓曼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钦扭,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤纫版,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后客情,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體其弊,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年膀斋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了梭伐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡概页,死狀恐怖籽御,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情惰匙,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布铃将,位于F島的核電站项鬼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏劲阎。R本人自食惡果不足惜绘盟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望悯仙。 院中可真熱鬧龄毡,春花似錦、人聲如沸锡垄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)货岭。三九已至路操,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間千贯,已是汗流浹背屯仗。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搔谴,地道東北人魁袜。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親峰弹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子店量,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容