美文网首页
android 折线图

android 折线图

作者: 南娇 | 来源:发表于2019-01-19 14:00 被阅读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的源码,注解写的很清楚,有的公共参数没有提出来,剩下的修改数据的方法自己加上就可以了

    相关文章

      网友评论

          本文标题:android 折线图

          本文链接:https://www.haomeiwen.com/subject/pctzdqtx.html