android 折线图

2019-01-19  本文已影响22人  南娇

优于别人并不高贵,真正的高贵是优于过去的自己

QQ截图20190119135102.png

步骤:
一、分析折线图哪些东西是需要我们写活得
1.折线的横纵坐标数据
2.折线横纵坐标的字体颜色、大小
3.折线的颜色
4.折线上点的颜色
5.坐标轴的颜色

二、根据上面的需求我们先自定义属性,基本就是下面这些

  <declare-styleable name="BrokenLineView">
         <!--坐标轴颜色-->
         <attr name="axisColor" format="color"/>
         <!--坐标颜色-->
         <attr name="coordinateColor" format="color"/>
         <!--折线颜色-->
         <attr name="brokenlineColor" format="color"/>
         <!--坐标字体大小-->
         <attr name="coordinateSize" format="dimension"/>
         <!--起始的渐变色-->
         <attr name="lineStartColor" format="color"/>
         <!--结束的渐变色-->
         <attr name="lineEndtColor" format="color"/>
     </declare-styleable>

三、然后就开始自定义view

 public class BrokenLineView extends View{

  private Context mContext;

//坐标轴颜色
private int mAxisColor;
//坐标颜色
private int mCoordinateColor;
//折线颜色
private int mBrokenlineColor;
//坐标字体大小
private int mCoordinateTextSize;

private int mWidth,mHeight;

//坐标轴画笔
private Paint mAxisPaint;

//虚线画笔
private Paint mDashedPaint;

//折线画笔
private Paint mBrokenlinPaint;

//阴影画笔
private Paint mShaderPaint;
//渐变阴影颜色数组
private int [] shadeColors;
private int startColor;
private int endColor;

private String [] mDataX={"0","20","40","60","80","100"};
private String [] mDataY={"1","4","7","10","13","16","19","22","25","28","31"};
private String [] mDatas={"10","40","5","8","36","66","90","10","10","10","10"};


//纵坐标最宽的字体宽度
private float textMaxX=0;
//横坐标的起始Y
private float startY;


public BrokenLineView(Context context) {
    this(context,null);
}

public BrokenLineView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs,0);
}

public BrokenLineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    this.mContext=context;

    TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.BrokenLineView);

    mAxisColor=array.getColor(R.styleable.BrokenLineView_axisColor,mAxisColor);
    mCoordinateColor=array.getColor(R.styleable.BrokenLineView_coordinateColor,mCoordinateColor);
    mBrokenlineColor=array.getColor(R.styleable.BrokenLineView_brokenlineColor,mBrokenlineColor);
    mCoordinateTextSize=array.getDimensionPixelSize(R.styleable.BrokenLineView_coordinateSize,mCoordinateTextSize);
    startColor=array.getColor(R.styleable.BrokenLineView_lineStartColor,startColor);
    endColor=array.getColor(R.styleable.BrokenLineView_lineEndtColor,endColor);
    shadeColors= new int[]{startColor, endColor};
    array.recycle();

    //初始化画笔
    initPaint();

}

private void initPaint() {
    mAxisPaint=new Paint();
    mAxisPaint.setColor(mAxisColor);
    mAxisPaint.setAntiAlias(true);
    mAxisPaint.setTextSize(mCoordinateTextSize);

    mDashedPaint=new Paint();
    mDashedPaint.setColor(mAxisColor);
    mDashedPaint.setAntiAlias(true);
    //绘制长度为2的虚线后在绘制长度为1的空白区,0位间隔
    mDashedPaint.setPathEffect(new DashPathEffect(new float[]{dp2px(mContext,2),dp2px(mContext,1)},0));

    mBrokenlinPaint=new Paint();
    mBrokenlinPaint.setAntiAlias(true);
    mBrokenlinPaint.setColor(mBrokenlineColor);

    mShaderPaint=new Paint();
    mShaderPaint.setAntiAlias(true);
  //        mShaderPaint.setColor(mBrokenlineColor);
     }

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    mWidth=MeasureSpec.getSize(widthMeasureSpec);
    mHeight=MeasureSpec.getSize(heightMeasureSpec);
}

@Override
protected void onDraw(Canvas canvas) {

    //画坐标x
    for(int i=0;i<mDataX.length;i++){

        //找出最宽的纵坐标
        getMaxWidth();

        String textX=mDataX[i];
        Paint.FontMetrics fm = mAxisPaint.getFontMetrics();
        float textHeigth=fm.bottom-fm.top;
        float textWidth=mAxisPaint.measureText(textX);
        float x=textMaxX-textWidth;

        getStartY(textHeigth);


        float baseLine=(((mDataX.length-i)*(startY/mDataX.length))-textHeigth)+textHeigth-fm.bottom+textHeigth/2;

        canvas.drawText(textX,x,baseLine,mAxisPaint);

        //画横向虚线

        setLayerType(LAYER_TYPE_SOFTWARE, null);
        if(i<5){
            canvas.drawLine(textMaxX+dp2px(mContext,5),startY-((i+1)*(startY/mDataX.length))
                    ,mWidth,startY-((i+1)*(startY/mDataX.length)),mDashedPaint);
        }

    }
    //画纵坐标
    canvas.drawLine(textMaxX+dp2px(mContext,5),0,textMaxX+dp2px(mContext,5),startY,mAxisPaint);
    //画横坐标
    canvas.drawLine(textMaxX+dp2px(mContext,5),startY,mWidth,startY,mAxisPaint);
    //画坐标轴Y
    for(int i=0;i<mDataY.length;i++){
        String textY=mDataY[i];
        Paint.FontMetrics fm = mAxisPaint.getFontMetrics();
        float textHeigth=fm.bottom-fm.top;
        float textWidth=mAxisPaint.measureText(textY);

        float x=textMaxX-(textWidth/2)+dp2px(mContext,5)+i*(mWidth-textMaxX+dp2px(mContext,5))/mDataY.length;
        float baseLine=(mHeight-textHeigth)+textHeigth-fm.bottom-dp2px(mContext,4);
        canvas.drawText(textY,x,baseLine,mAxisPaint);

        //画纵向虚线
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        canvas.drawLine(textMaxX+dp2px(mContext,5)+(i+1)*(mWidth-textMaxX+dp2px(mContext,5))/mDataY.length,startY
                ,textMaxX+dp2px(mContext,5)+(i+1)*(mWidth-textMaxX+dp2px(mContext,5))/mDataY.length,0,mDashedPaint);
    }

    //画折线
    Path mPathShader=new Path();
    mPathShader.moveTo(textMaxX+dp2px(mContext,5),startY);
    for(int i=0;i<mDatas.length;i++){
            float dataStart=Float.valueOf(mDatas[i]);

            float X=textMaxX+dp2px(mContext,5)+i*(mWidth-textMaxX+dp2px(mContext,5))/mDataY.length;
            float Y=startY-startY*(dataStart/100);
            if((i+1)<mDatas.length){
                    float dataEnd=Float.valueOf(mDatas[i+1]);
                    float endX=textMaxX+dp2px(mContext,5)+(i+1)*(mWidth-textMaxX+dp2px(mContext,5))/mDataY.length;
                    float endY=startY-startY*(dataEnd/100);
                    canvas.drawLine(X,Y,endX,endY,mBrokenlinPaint);
            }


            mPathShader.lineTo(X,Y);



    }
    //画填充阴影
    mPathShader.lineTo(textMaxX+dp2px(mContext,5)+(mDataY.length-1)*(mWidth-textMaxX+dp2px(mContext,5))/mDataY.length,startY);
    Shader mShader=new LinearGradient(0, 0, 0, getHeight(), shadeColors, null, Shader.TileMode.CLAMP);
    mShaderPaint.setShader(mShader);
    canvas.drawPath(mPathShader,mShaderPaint);

    //画折线点
    for(int i=0;i<mDatas.length;i++){
        float dataStart=Float.valueOf(mDatas[i]);
        float X=textMaxX+dp2px(mContext,5)+i*(mWidth-textMaxX+dp2px(mContext,5))/mDataY.length;
        float Y=startY-startY*(dataStart/100);
        //画折点的原点
        canvas.drawCircle(X,Y,dp2px(mContext,2),mBrokenlinPaint);
    }



}

private void getStartY(float textHeigth) {
    startY=mHeight-textHeigth-dp2px(mContext,5);
}


//找出最宽的字符串的宽度
private void getMaxWidth() {
    for(int i=0;i<mDataX.length;i++){
        String text=mDataX[i];
        if(mAxisPaint.measureText(text)>textMaxX){
            textMaxX=mAxisPaint.measureText(text);
        }
    }
}

private int dp2px(Context context, float dpValue) {
    float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dpValue * scale + 0.5f);
}

 }

上面就是自定义view的源码,注解写的很清楚,有的公共参数没有提出来,剩下的修改数据的方法自己加上就可以了

上一篇下一篇

猜你喜欢

热点阅读