1. 程式人生 > >android自定義View,實現折線圖(二)

android自定義View,實現折線圖(二)

效果圖:

LineChartView類:

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<Integer, PageViewData> dataTotal;//用於得儲存傳入的總資料
    private float mRange[]=new float[3];

    //傳三個數值範圍
    public void setRange(float[] range) {
        mRange = range;
    }

    //用一個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<Integer, PageViewData> 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<Integer, PageViewData> 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()) {
            String date = dataTotal.get(key).getDate();
            float value = dataTotal.get(key).getPageViewValue();

            if(value <= mRange[0]){
                mPaintCircle.setColor(Color.parseColor("#FF0000"));
            }else if(value >= mRange[2]) {
                mPaintCircle.setColor(Color.parseColor("#FBAD5F"));
            }else{
                mPaintCircle.setColor(Color.parseColor("#C8E1A8"));
            }
            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();

    }
}

xml檔案:
<HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none">
        <com.xx.xx.LineChartView
            android:id="@+id/line_chart_view_item"
            android:layout_width="wrap_content"
            android:layout_height="160dp"/>
 </HorizontalScrollView>

MainActivity:

public class MainActivity extends Activity {    
     private LineChartView mLineChartView;
     private HashMap<Integer,PageViewData> mDataPageView;
 @Override    
 protected void onCreate(Bundle savedInstanceState) {    
  super.onCreate(savedInstanceState);    
  setContentView(R.layout.activity_main);
  mLineChartView = (LineChartView) findViewById(R.id.line_chart_view_item);
  initDataPageView();    
 }
 private void initDataPageView() {
        mDataPageView = new HashMap<>();
        mDataPageView.put(1,new PageViewData(1,"5/1",4.0f));
        mDataPageView.put(2,new PageViewData(2,"5/2",8.5f));
        mDataPageView.put(3,new PageViewData(3,"5/3",5.4f));
        mDataPageView.put(4,new PageViewData(4,"5/4",4.6f));
        mDataPageView.put(5,new PageViewData(5,"5/5",6.2f));
        mDataPageView.put(6,new PageViewData(6,"5/6",4.2f));
        mDataPageView.put(7,new PageViewData(7,"5/7",10.4f));
        mDataPageView.put(8,new PageViewData(8,"5/8",4.4f));
        mDataPageView.put(9,new PageViewData(9,"5/9",5.5f));
        mDataPageView.put(10,new PageViewData(10,"5/10",6.0f));
        mDataPageView.put(11,new PageViewData(11,"5/11",5.4f));
        mDataPageView.put(12,new PageViewData(12,"5/12",3.9f));
        mDataPageView.put(13,new PageViewData(13,"5/13",4.2f));
        mDataPageView.put(14,new PageViewData(14,"5/14",8.0f));
        mDataPageView.put(15,new PageViewData(15,"5/15",11.4f));
        mLineChartView.setDataTotal(mDataPageView);
        mLineChartView.setRange(new float[]{4.4f,7f,10f});//範圍
        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));
    }


下載資源傳送門入口: