Android鬼點子 100行程式碼,搞定柱狀圖!

我是綠色大米呀發表於2019-02-26

最近,專案中遇到一個地方,要用到柱狀圖。所以這篇文章主要講怎麼搞一個柱子。
100行程式碼,搞定柱狀圖!

qq.png

我的印象中柱子是這樣的。

柱子

恩,簡單,一個View直接放到xml,搞定!
但,設計師給的柱子是這樣的:

設計圖.png

圓角,頭頂帶數字。恩,這樣用drawable也可以搞定。
但是,這個柱子是有一個動畫的,就是進入到介面的時候柱子不斷的長高。
這樣的話,綜合考慮還是用自定義View來做比較簡便。下面講一下思路。首先忽略動畫,先把靜態的效果做出來。

關於尺寸

控制元件尺寸直接來自xml中的設定,無需進行onMeasure測量。所以使用getWidth和getHeight獲取高度。

關於資料範圍

資料如果是一個柱子單獨顯示,則資料的範圍不是很重要,但是柱狀圖通常是由很多柱子並列顯示的,而這些柱子的單位高度都應該是一樣的,所以提供設定最大值的範圍,最小值就是0.

關於數字的文字大小

由於柱子的寬度就是整個View的寬度,所以數字的寬度不能超過柱子的寬度。因為這個原因,文字的size需要動態計算。意思就是 0和100000這兩個數字顯示的時候,文字的大小是不一樣的。

關於邊界值

0,是一個邊界值(最小值),當顯示0的時候,並不是柱子不顯示的,而是顯示一個最小高度的。

關於動畫

不停的設定值,就會形成動畫。意思是先設定資料1,然後緊接著設資料2.3.4.5……一直到最終的顯示值,就會有動畫效果。但是如果最終數值很大,1,1,1的增加就會很慢,動畫時間很長。

程式碼如下:

public class PPColumn extends View {
    int MAX = 100;//最大
    int corner = 40;
    int data = 0;//顯示的數
    int tempData = 0;
    int textPadding = 20;
    Paint mPaint;
    int mColor;

    Context mContext;

    public PPColumn(Context context) {
        super(context);
        mContext = context;
    }

    public PPColumn(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        initPaint();
    }

    public PPColumn(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mColor = mContext.getResources().getColor(R.color.colorPrimary);
        mPaint.setColor(mColor);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        if(data == 0){
            mPaint.setTextSize(getWidth() / 2);
            RectF oval3 = new RectF(0, getHeight() -  DPUnitUtil.px2dip(mContext,20), getWidth(), getHeight());// 設定個新的長方形
            canvas.drawRoundRect(oval3,  DPUnitUtil.px2dip(mContext,corner),  DPUnitUtil.px2dip(mContext,corner), mPaint);

            canvas.drawText("0",
                    getWidth() * 0.5f - mPaint.measureText("0") * 0.5f ,
                    getHeight() -  DPUnitUtil.px2dip(mContext,20) - 2 * DPUnitUtil.px2dip(mContext,textPadding),
                    mPaint);
            return;
        }

        //防止數值很大的的時候,動畫時間過長
        int step = data /100 + 1;

        if(tempData < data - step){
            tempData = tempData + step;
        }else{
            tempData = data;
        }
        //畫圓角矩形
        String S = tempData + "";

        //一個字和兩,三個字的字號相同
        if(S.length()<4){
            mPaint.setTextSize(getWidth() / 2);
        }else{
            mPaint.setTextSize(getWidth() / (S.length()-1));
        }

        float textH = mPaint.ascent() + mPaint.descent();
        float MaxH = getHeight() - textH - 2 * DPUnitUtil.px2dip(mContext,textPadding);
        //圓角矩形的實際高度
        float realH = MaxH / MAX * tempData;
        RectF oval3 = new RectF(0, getHeight() - realH, getWidth(), getHeight());// 設定個新的長方形
        canvas.drawRoundRect(oval3,  DPUnitUtil.px2dip(mContext,corner),  DPUnitUtil.px2dip(mContext,corner), mPaint);

        //寫數字
        canvas.drawText(S,
                getWidth() * 0.5f - mPaint.measureText(S) * 0.5f ,
                getHeight() - realH - 2 * DPUnitUtil.px2dip(mContext,textPadding),
                mPaint);

        if(tempData != data){
            postInvalidate();
        }
    }

    public void setData(int data, int MAX){
        this.data = data;
        tempData = 0;
        this.MAX = MAX;
        postInvalidate();
    }

}

複製程式碼

我是在xml中這樣使用的,也就是上面效果的樣子。

<LinearLayout
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1">
                <View
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="0.2" />
                <com.allrun.arsmartelevatorformanager.widget.PPColumn
                    android:id="@+id/weihu_column"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1" />

                <View
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="2.4" />

                <com.allrun.arsmartelevatorformanager.widget.PPColumn
                    android:id="@+id/weixiu_column"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1" />

                <View
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="2.4" />

                <com.allrun.arsmartelevatorformanager.widget.PPColumn
                    android:id="@+id/jiuyuan_column"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1" />
                <View
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="0.2" />

            </LinearLayout>
複製程式碼

使用,設定值。Max最後要加1,防止0.幾的時候計算錯誤。

int max = (int) (Math.max(Math.max(weihu, weixiu), jiuyuan) * 1.2) + 1;
weihuColumn.setData(weihu, max);
複製程式碼

最後效果圖

cc.gif

相關文章