Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義view之繪制實用型的柱形圖和折線圖

Android自定義view之繪制實用型的柱形圖和折線圖

編輯:關於Android編程

概述:

前幾天突然需要做兩種圖表——柱形圖、折線圖,於是第一反應是先看看網上有沒有現成的,結果有是有,但都不是我想要的,而且大多數不是用純android代碼完成,HTML5似乎完成這類工作要容易得多,但是我本人並不會HTML5,只能黯然神傷,掩面流淚,最終只能自己敲代碼了。

**知識點:**android自定義view、圖形圖像、Fragment、MVC模式。

Demo

界面是模仿紅圈營銷搭建的

折線圖:
這裡寫圖片描述

代碼,注釋很詳細,直接看代碼就行了:

public class LineChartView extends View {

    private int width;
    private int height;
    private float maxValue;//傳入數據的最大值
    private int dataNum;//數據總數

    private Paint mPaintBg;//報表背景畫筆
    private Paint mPaintCoveredBg;//用於畫數據覆蓋部分
    private Paint mPaintChartLine;//用於畫報表的網格
    private Paint mPaintDataLine;//用於畫數據連線
    private Paint mPaintTextDate;//用於畫日期文本
    private Paint mPaintCircle;//用於畫空心圓
    private Paint mPaintFilledCircle;//用於畫實心圓
    private Paint mPaintTextValue;//用於畫數據訪問量值

    private Path path;

    private HashMap dataTotal;//用於得存儲傳入的總數據

    //用一個setPaints()方法,設定所有畫筆的屬性,增加代碼靈活性
    public void setPaints(int bgColor, int coveredBgColor, int chartLineColor
            , int dataLineColor, int textDateColor, int filledCircleColor, int circleColor, int textValueColor) {

        mPaintBg.setColor(bgColor);
        mPaintBg.setStyle(Paint.Style.FILL);

        mPaintCoveredBg.setColor(coveredBgColor);
        mPaintCoveredBg.setStyle(Paint.Style.FILL);

        mPaintCircle.setColor(circleColor);
        mPaintCircle.setStyle(Paint.Style.STROKE);
        mPaintCircle.setStrokeWidth(5);
        mPaintCircle.setAntiAlias(true);

        mPaintFilledCircle.setColor(filledCircleColor);
        mPaintFilledCircle.setStyle(Paint.Style.FILL);
        mPaintFilledCircle.setAntiAlias(true);

        mPaintChartLine.setColor(chartLineColor);
        mPaintChartLine.setStyle(Paint.Style.STROKE);
        mPaintChartLine.setAntiAlias(true);

        mPaintDataLine.setColor(dataLineColor);
        mPaintDataLine.setStyle(Paint.Style.STROKE);
        mPaintDataLine.setStrokeWidth(SizeConvert.dip2px(getContext(), 5));
        mPaintDataLine.setAntiAlias(true);

        mPaintTextDate.setColor(textDateColor);
        mPaintTextDate.setTextSize(SizeConvert.dip2px(getContext(), 10));
        mPaintTextDate.setTextAlign(Paint.Align.CENTER);
        mPaintTextDate.setAntiAlias(true);

        mPaintTextValue.setColor(textValueColor);
        mPaintTextValue.setTextSize(SizeConvert.dip2px(getContext(), 12));
        mPaintTextValue.setTextAlign(Paint.Align.CENTER);
        mPaintTextValue.setAntiAlias(true);

        //重繪
        invalidate();
    }


    //用於設定傳入的總數據
    public void setDataTotal(HashMap dataTotal) {
        this.dataTotal = dataTotal;
        invalidate();
    }

    public LineChartView(Context context) {
        super(context);
    }

    public LineChartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaintBg = new Paint();
        mPaintCoveredBg = new Paint();
        mPaintCircle = new Paint();
        mPaintChartLine = new Paint();
        mPaintDataLine = new Paint();
        mPaintTextDate = new Paint();
        mPaintTextValue = new Paint();
        mPaintFilledCircle = new Paint();
        path = new Path();

        dataTotal = new HashMap<>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //當總數據已經傳入,即不為空時,根據總數據中數據個數設定view的總寬
        if (dataTotal != null) {
            width = (dataTotal.size() - 1) * xAddedNum + chartMarginHorizontal * 2;
            getMaxValue(dataTotal);
        }
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    /**
     * 用於得到總數據中最大數據
     * @param dataTotal 總數據
     */
    private void getMaxValue(HashMap dataTotal) {
        maxValue = 0;
        dataNum = 0;
        for (int key : dataTotal.keySet()) {
            if (dataTotal.get(key).getPageViewValue() > maxValue) {
                maxValue = dataTotal.get(key).getPageViewValue();
            }
            dataNum++;
        }
    }

    private int mChartHeight;//折線圖的高
    private int mChartWidth;//折線圖的
    private int startX = SizeConvert.dip2px(getContext(), 10);//開始繪制的x坐標
    private int startY = SizeConvert.dip2px(getContext(), 5);//開始繪制的y坐標
    private int chartMarginBottom = SizeConvert.dip2px(getContext(), 30);//折線圖距離父控件底部距離
    private int chartMarginHorizontal = SizeConvert.dip2px(getContext(), 12);//折線圖距離父控件左右的距離
    private int valueAlignLeft = SizeConvert.dip2px(getContext(), 0);//value參數文本距離左邊距離
    private int dateAlignLeft = SizeConvert.dip2px(getContext(), 0);//date參數文本距離左邊距離
    private int valueAlignBottom = SizeConvert.dip2px(getContext(), 5);//value參數文本距離底部距離
    private int dateAlignBottom = SizeConvert.dip2px(getContext(), 10);//date參數文本距離底部距離
    private int xAddedNum = SizeConvert.dip2px(getContext(), 60);//繪制折線圖時每次移動的x軸距離
    private int yAddedNum;//繪制折線圖時每次移動的y軸距離
    private boolean isDrawFirst;//是否是第一次繪制
    private float circleFilledRadius = SizeConvert.dip2px(getContext(), 5);//外圓半徑
    private float circleRadius = SizeConvert.dip2px(getContext(), 3);//內圓半徑

    private float firstX;//第一個點的x軸坐標
    private float firstY;//第一個點的y軸坐標

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        isDrawFirst = true;
        mChartHeight = height - chartMarginBottom;
        yAddedNum = mChartHeight / 4;
        mChartWidth = width - chartMarginHorizontal * 2;

        canvas.drawRect(startX, startY, startX + mChartWidth, startY + mChartHeight, mPaintBg);
        for (int key : dataTotal.keySet()) {
            float value = dataTotal.get(key).getPageViewValue();
            if (isDrawFirst) {
                //當第一次繪制時得到第一個點的橫縱坐標
                firstX = startX;
                firstY = startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight;
                path.moveTo(firstX, firstY);
                isDrawFirst = false;
            }
            //每循環一次,將path線性相位一次
            path.lineTo(startX, startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight);
            startX += xAddedNum;
        }
        //重新給startX賦值
        startX = SizeConvert.dip2px(getContext(), 10);
        //畫出折線
        canvas.drawPath(path, mPaintDataLine);
        //畫出折線以下部分的顏色
        path.lineTo(startX + mChartWidth, startY + mChartHeight);
        path.lineTo(startX, startY + mChartHeight);
        path.lineTo(firstX, firstY);
        canvas.drawPath(path, mPaintCoveredBg);

        //畫出每個點的圓圈,和對應的文本
        for (int key : dataTotal.keySet()) {
            int date = dataTotal.get(key).getDate();
            float value = dataTotal.get(key).getPageViewValue();
            canvas.drawCircle(startX, startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight, circleFilledRadius, mPaintFilledCircle);
            canvas.drawCircle(startX, startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight, circleRadius, mPaintCircle);
            canvas.drawText(date + , startX + dateAlignLeft, height - dateAlignBottom, mPaintTextDate);
            canvas.drawText(value + , startX + valueAlignLeft, startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight - valueAlignBottom, mPaintTextValue);

            startX += xAddedNum;
        }

        //在次使startX回到初始值
        startX = SizeConvert.dip2px(getContext(), 10);
        /**
         * 畫出網格
         */
        //豎線
        for (int i = 0; i < dataNum; i++) {
            canvas.drawLine(startX + i * xAddedNum, startY, startX + i * xAddedNum, startY + mChartHeight, mPaintChartLine);
        }

        //橫線
        for (int i = 0; i < 5; i++) {
            canvas.drawLine(startX, startY + i * yAddedNum, startX + mChartWidth, startY + i * yAddedNum, mPaintChartLine);
        }

        path.reset();

    }
}

柱形圖:
這裡寫圖片描述

代碼:<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> /** * 柱形圖 */ public class HistogramView extends View { private int width; private int height; private Paint mBgPaint; private Paint mHistogramBgPaint; private Paint mHistogramPaint; private Paint mTextPaint; private HashMap dataTotal; public void setPaints(int bgColor,int histogramBgColor,int histogramColor,int textColor){ mBgPaint.setColor(bgColor); mBgPaint.setStyle(Paint.Style.FILL); mHistogramBgPaint.setColor(histogramBgColor); mHistogramBgPaint.setStyle(Paint.Style.FILL); mHistogramPaint.setColor(histogramColor); mHistogramPaint.setStyle(Paint.Style.FILL); mTextPaint.setColor(textColor); mTextPaint.setTextSize(SizeConvert.dip2px(getContext(), 9)); mTextPaint.setTextAlign(Paint.Align.CENTER); invalidate(); }; public void setDataTotal(HashMap dataTotal) { this.dataTotal = dataTotal; invalidate(); } public HistogramView(Context context) { super(context); } public HistogramView(Context context, AttributeSet attrs) { super(context, attrs); mHistogramBgPaint = new Paint(); mHistogramPaint = new Paint(); mTextPaint = new Paint(); mBgPaint = new Paint(); dataTotal = new HashMap<>(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if(dataTotal!=null){ width = dataTotal.size()*SizeConvert.dip2px(getContext(), 40); } height = getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec); setMeasuredDimension(width, height); } private int mHistogramHeight; int startX = SizeConvert.dip2px(getContext(), 20); int startY = SizeConvert.dip2px(getContext(),20); int radius = 45; int greyValueAlignLeft = SizeConvert.dip2px(getContext(), 5); int nameAlignLeft = SizeConvert.dip2px(getContext(), 15); int greyValueAlignBottom = SizeConvert.dip2px(getContext(), 5); int nameAlignBottom = SizeConvert.dip2px(getContext(), 15); int histogramWidth = SizeConvert.dip2px(getContext(), 8); int xAddedNum = SizeConvert.dip2px(getContext(), 40); int histogramAlignTop = SizeConvert.dip2px(getContext(), 2); @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mHistogramHeight = height-SizeConvert.dip2px(getContext(),40); canvas.drawRect(0,startY,width,mHistogramHeight,mBgPaint); for(int key:dataTotal.keySet()){ String name = dataTotal.get(key).getName(); int greyValue = dataTotal.get(key).getGreyValue(); canvas.drawText(greyValue + %, startX + greyValueAlignLeft, startY-greyValueAlignBottom , mTextPaint); canvas.drawRect(startX, startY+histogramAlignTop, startX + histogramWidth, mHistogramHeight, mHistogramBgPaint); canvas.drawRect(startX, startY+(1f - greyValue / 100f) * (mHistogramHeight - startY-histogramAlignTop)+histogramAlignTop, startX + histogramWidth, mHistogramHeight, mHistogramPaint); canvas.save(); canvas.rotate(-radius, startX,height); canvas.drawText(name, startX + nameAlignLeft, height-nameAlignBottom, mTextPaint); canvas.restore(); startX+=xAddedNum; } startX = SizeConvert.dip2px(getContext(), 20); } }

Fragment

public class FragmentChart extends Fragment implements View.OnClickListener{

    private RelativeLayout mItemFirst;
    private RelativeLayout mItemSecond;
    private RelativeLayout mItemThird;
    private RelativeLayout mItemForth;

    private HistogramView mHistogramView;
    private HashMap mDataHistogramTotal;
    private boolean isShowHistogram = false;

    private LineChartView mLineChartView;
    private HashMap mDataPageView;
    private boolean isShowSecondItem = false;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.content_chart,null);
        mItemFirst = (RelativeLayout) view.findViewById(R.id.first_page_item_1);
        mItemSecond = (RelativeLayout) view.findViewById(R.id.first_page_item_2);
        mItemThird = (RelativeLayout) view.findViewById(R.id.first_page_item_3);
        mItemForth = (RelativeLayout) view.findViewById(R.id.first_page_item_4);

        mHistogramView = (HistogramView) view.findViewById(R.id.histogram_view_item_1);
        mLineChartView = (LineChartView) view.findViewById(R.id.line_chart_view_item_2);

        mItemFirst.setOnClickListener(this);
        mItemSecond.setOnClickListener(this);
        mItemThird.setOnClickListener(this);
        mItemForth.setOnClickListener(this);

        initDataHistogram();
        initDataPageView();

        return view;
    }

    private void initDataPageView() {
        mDataPageView = new HashMap<>();
        mDataPageView.put(1,new PageViewData(1,9,16));
        mDataPageView.put(2,new PageViewData(2,10,18));
        mDataPageView.put(3,new PageViewData(3,11,33));
        mDataPageView.put(4,new PageViewData(4,12,97));
        mDataPageView.put(5,new PageViewData(5,13,46));
        mDataPageView.put(6,new PageViewData(6,14,55));
        mDataPageView.put(7,new PageViewData(7,15,11));
        mDataPageView.put(8,new PageViewData(8,16,22));
        mDataPageView.put(9,new PageViewData(9,17,8));
        mDataPageView.put(10,new PageViewData(10,18,19));
        mDataPageView.put(11,new PageViewData(11,16,22));

        mLineChartView.setDataTotal(mDataPageView);
        mLineChartView.setPaints(Color.argb(255,225, 250, 250),
                Color.argb(255,234, 234, 250), Color.argb(255,74,208, 204),
                Color.argb(255,105, 210, 249),Color.argb(255,203, 203, 203)
                ,Color.argb(255,255, 255, 255),Color.argb(255,105, 210, 249),Color.argb(255,105, 210, 249));
    }

    private void initDataHistogram(){
        mDataHistogramTotal = new HashMap<>();
        mDataHistogramTotal.put(1,new HistogramData(1,海萌,100));
        mDataHistogramTotal.put(2,new HistogramData(2,濤濤,18));
        mDataHistogramTotal.put(3,new HistogramData(3,火風,17));
        mDataHistogramTotal.put(4,new HistogramData(4,周傑倫,16));
        mDataHistogramTotal.put(5,new HistogramData(5,王寶強,15));
        mDataHistogramTotal.put(6,new HistogramData(6,林俊傑,14));
        mDataHistogramTotal.put(7,new HistogramData(7,孫悟空,11));
        mDataHistogramTotal.put(8,new HistogramData(8,鐘航,10));
        mDataHistogramTotal.put(9,new HistogramData(9,小明,8));
        mDataHistogramTotal.put(10, new HistogramData(10, 小紅, 5));

        mHistogramView.setDataTotal(mDataHistogramTotal);
        mHistogramView.setPaints(Color.argb(255,250, 250, 250),
                Color.argb(255,238, 238, 238), Color.argb(255,240,141, 77),
                Color.argb(255,168, 168, 168));
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.first_page_item_1:
                isShowHistogram = !isShowHistogram;
                if(isShowHistogram) {
                    mHistogramView.setVisibility(View.VISIBLE);
                }else{
                    mHistogramView.setVisibility(View.GONE);
                }
                break;
            case R.id.first_page_item_2:
                isShowSecondItem= !isShowSecondItem;
                if(isShowSecondItem) {
                    mLineChartView.setVisibility(View.VISIBLE);
                }else{
                    mLineChartView.setVisibility(View.GONE);
                }
                break;
            case R.id.first_page_item_3:
                break;
            case R.id.first_page_item_4:
                break;
        }
    }
}

主活動:

public class MainActivity extends FragmentActivity {

    private FragmentChart mFragmentChart;
    private RadioGroup mRadioGroup;
    private FragmentTransaction transaction;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mFragmentChart = new FragmentChart();
        mFragmentManager = getSupportFragmentManager();
        transaction = mFragmentManager.beginTransaction();
        transaction.add(R.id.frame_layout, mFragmentChart);
        transaction.commit();
        mRadioGroup = (RadioGroup) findViewById(R.id.radiogroup);

        mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {

                switch (checkedId) {
                    case R.id.button1:
                        transaction = mFragmentManager.beginTransaction();
                        transaction.hide(mFragmentChat);
                        transaction.hide(mFragmentSetting);
                        transaction.hide(mFragmentWork);
                        transaction.show(mFragmentChart);
                        transaction.commit();
                        break;

                }
            }
        });
    }
}

activity_main:



    <framelayout android:id="@+id/frame_layout" android:layout_height="wrap_content" android:layout_weight="1" android:layout_width="match_parent">
    </framelayout>

    

        

        

        

        

    

content_chart:




     

            

            

                

                    

                    

                        

                        
                    

                

                

    
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved