自定義折線圖筆記

自定義折線圖的需求在 APP 開發(fā)中好像很常見了,事實(shí)上用一些第三方庫(kù)來繪制折線圖很容易實(shí)現(xiàn)雏逾,但感覺一個(gè)類能搞定的事情去接入一個(gè)庫(kù)好像有點(diǎn)不和諧啊一罩。本著學(xué)習(xí)的目的,繪制了一個(gè)折線圖嫌拣,下面上效果圖:

效果圖.png

我的自定義 view

  • 1.新建 Zhexiantu 繼承之 View ,重寫下面兩個(gè)構(gòu)造函數(shù),并在里面做一些初始化操作呆躲。
public Zhexiantu(Context context) {
        super(context);
        this.mContext = context;
        init();
    }

 public Zhexiantu(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Zhexiantu);
        myBg = array.getColor(R.styleable.Zhexiantu_my_bg, 0xFFF7F7F7);  //默認(rèn)值必須
        linechartColor = array.getColor(R.styleable.Zhexiantu_linechart_color,0xFF90E7FD);
        linechartSize = (int) array.getDimension(R.styleable.Zhexiantu_linechart_size,3);
        linechartBg = array.getColor(R.styleable.Zhexiantu_linechart_bg,0xFFFFFFFF);
        padding = (int) array.getDimension(R.styleable.Zhexiantu_linechart_padding,16);

        init();
        array.recycle(); //取完值异逐,記得回收
    }

第二個(gè)構(gòu)造函數(shù)中相比第一個(gè)構(gòu)造函數(shù)多了一些自定義屬性取值的操作,自定義屬性需要在 res/values 文件夾下的 styles.xml 文件下定義屬性插掂,eg:

<!--自定義屬性-->
    <declare-styleable name="Zhexiantu">
        <attr name="my_bg" format="color"/>
        <attr name="linechart_color" format="color"/>
        <attr name="linechart_size" format="dimension"/>
        <attr name="linechart_bg" format="color"/>
        <attr name="linechart_padding" format="dimension"/>
    </declare-styleable>

以上兩步都完成就可以在我們自己的自定義控件上使用自定義屬性了灰瞻,eg:

  <com.lisheny.lenovo.myviewstudy.canvas.Zhexiantu
            android:id="@+id/zhexiantu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:linechart_color="@color/color2"
            app:linechart_bg="@color/color13"/>

另外腥例,附上 Paint 屬性設(shè)置的詳解 http://wuxiaolong.me/2016/08/20/Paint/

  • 2.重寫 onMeasure 方法,計(jì)算獲取畫布的寬高并計(jì)算尺 X酝润、Y軸的區(qū)間間隔
 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int mode = MeasureSpec.getMode(heightMeasureSpec);
        switch (mode) {
            case MeasureSpec.AT_MOST:                             //(wrap_content)
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
                mHeigt = 3 * mWidth / 5;
                break;
            case MeasureSpec.EXACTLY:                             //固定尺寸(如100dp)
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
                mHeigt = MeasureSpec.getSize(heightMeasureSpec);
                break;
            case MeasureSpec.UNSPECIFIED:                         //比重 (layout_weight="1")
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
                mHeigt = 3 * mWidth / 5;
                break;
        }

        //X軸區(qū)間間隔
        xDistance = (mWidth - 4 * dp2px(padding)) / (xText.length - 1);
        //Y軸區(qū)間間隔
        yDistance = (mHeigt - 2 * dp2px(padding)) / (yText.length - 1);
        setMeasuredDimension((int) mWidth, (int) mHeigt);
    }

通過 int mode = MeasureSpec.getMode(heightMeasureSpec); 獲取測(cè)量模式燎竖,根據(jù)不同的測(cè)量模式將寬高設(shè)置為合理的相應(yīng)值。關(guān)于這三種測(cè)量模式的介紹:

  1. UNSPECIFIED ==》父容器沒有對(duì)當(dāng)前View有任何限制袍祖,當(dāng)前View可以任意取尺寸
  2. EXACTLY ==》當(dāng)前的尺寸就是當(dāng)前View應(yīng)該取的尺寸
  3. AT_MOST ==》當(dāng)前尺寸是當(dāng)前View能取的最大尺寸

理解否底瓣?不理解沒事,我們知道什么情況下調(diào)用什么模式就行:

  1. xml 中 設(shè)置 wrap_content 時(shí)蕉陋,會(huì)走 AT_MOST 模式捐凭;
  2. xml 中 設(shè)置 固定尺寸(如100dp) 時(shí),會(huì)走 EXACTLY 模式凳鬓;
  3. 這種使用比較少茁肠,xml 中 設(shè)置 比重 layout_weight="1" 時(shí),會(huì)走 EXACTLY 模式缩举;

注:onMeasure 函數(shù)會(huì)多次調(diào)用

  • 3.接下來就是重寫 onDraw 函數(shù)繪制 View
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //繪制畫布顏色
        canvas.drawColor(myBg);

        drawTextAndGrid(canvas, textPaint, gridPaint);
        drawLineChart(canvas);
        drawDots(canvas);
    }

繪制步驟:

  1. 繪制畫布顏色垦梆,背景
  2. 繪制X、Y軸的坐標(biāo)值和表格
  3. 繪制折線
  4. 繪制小圓點(diǎn)
  5. 完成=龊ⅰM行伞!

特別的:計(jì)算Y軸的刻度

 /**
     * 根據(jù)輸入數(shù)據(jù)值的到對(duì)應(yīng)Y軸坐標(biāo)
     *
     * 這里需求:Y軸坐標(biāo)增長(zhǎng) 隨屏幕之上而下增加  注:變量盡量用浮點(diǎn)型辽慕,避免精度丟失
     * 公式:Y = Y軸開始值 + 每份坐標(biāo)刻度所占Y軸長(zhǎng)度的量{Y軸長(zhǎng)度/總刻度} * 當(dāng)前刻度值{value-min}
     * 即:Y = Y軸開始值{ dp2px(padding) + dp2px(5)} + 每份坐標(biāo)刻度所占Y軸長(zhǎng)度的量{(yDistance * (yText.length - 1)) / (yText[yText.length-1]-yText[0])} * 當(dāng)前刻度值{(value - yText[0])}
     *
     * @param value
     * @return
     */
    private float getYcoordinate(float value) {
        return dp2px(padding) + dp2px(5) + (yDistance * (yText.length - 1)) / (yText[yText.length - 1] - yText[0]) * (value - yText[0]);
    }

其中:總刻度 = 最大Y刻度值(max) - 最小Y刻度值(min)

  • 最后:折線圖的繪制總的來說很簡(jiǎn)單京腥,主要點(diǎn)是載入數(shù)據(jù)的刻度值要和Y軸相對(duì)應(yīng),理解計(jì)算出Y軸坐標(biāo)的公式溅蛉,折線圖的繪制就簡(jiǎn)單了公浪,以上代碼不全,若要查看完成 Demo 船侧,點(diǎn)擊此處傳送欠气。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市镜撩,隨后出現(xiàn)的幾起案子预柒,更是在濱河造成了極大的恐慌,老刑警劉巖袁梗,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卫旱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡围段,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門投放,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奈泪,“玉大人,你說我怎么就攤上這事±晕Γ” “怎么了拜姿?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)冯遂。 經(jīng)常有香客問我蕊肥,道長(zhǎng),這世上最難降的妖魔是什么蛤肌? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任壁却,我火速辦了婚禮,結(jié)果婚禮上裸准,老公的妹妹穿的比我還像新娘展东。我一直安慰自己,他們只是感情好炒俱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布盐肃。 她就那樣靜靜地躺著,像睡著了一般权悟。 火紅的嫁衣襯著肌膚如雪砸王。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天峦阁,我揣著相機(jī)與錄音谦铃,去河邊找鬼。 笑死拇派,一個(gè)胖子當(dāng)著我的面吹牛荷辕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播件豌,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼疮方,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了茧彤?” 一聲冷哼從身側(cè)響起骡显,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎曾掂,沒想到半個(gè)月后惫谤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡珠洗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年溜歪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片许蓖。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝴猪,死狀恐怖调衰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情自阱,我是刑警寧澤嚎莉,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站沛豌,受9級(jí)特大地震影響趋箩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜加派,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一叫确、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哼丈,春花似錦启妹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至车胡,卻和暖如春檬输,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背匈棘。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工丧慈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人主卫。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓逃默,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親簇搅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子完域,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,085評(píng)論 25 707
  • 前言 支付寶有個(gè)查看月賬單的功能,最近一直在學(xué)習(xí)自定義View,于是就嘗試著自己實(shí)現(xiàn)了一個(gè)類似的折線圖瘩将。 下面是支...
    neo1949閱讀 4,056評(píng)論 2 13
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)吟税、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,096評(píng)論 4 62
  • 前晚姿现,正當(dāng)做著一個(gè)令人沮喪的夢(mèng)肠仪,忍不住傷心淚流之時(shí),聽到小女抽噎的聲音备典,拼命從夢(mèng)中醒來异旧。只見傻丫頭一吸一頓地,眼角...
    邊邊緣閱讀 240評(píng)論 11 8
  • 我也可以是個(gè)細(xì)心的人 這真是個(gè)驚人的發(fā)現(xiàn)提佣。 丟三落四 毛毛躁躁 走路動(dòng)不動(dòng)就踢翻個(gè)凳子 這是典型我的作風(fēng)泽艘。 一般這...
    荔枝PPTer閱讀 2,249評(píng)論 0 3