美文网首页
自定义view - 折线图

自定义view - 折线图

作者: 适量哥 | 来源:发表于2017-11-16 11:41 被阅读45次

    自定义 view 在 Android 开发中会经常用到,本项目是一个很好的学习例子,如果有空可以看一下哟!

    来看下效果图:
    linechart.gif
    自定义 view 代码:
    /**
     * Created by kn on 2016/11/1.
     * <p/>
     * 折线图
     */
    public class LineChart extends View {
    
        private int mWidth, mHeight;//View 的宽和高
    
        private float mFontSize = 12;//字体的大小
        private float mStrokeWidth = 1.5f;//线条的宽度
        private float mPointRadius = 2;//点的半径
        private int mDateTextColor = Color.parseColor("#cfcfcf");//日期字体颜色
        private int mDarkColor = Color.parseColor("#5b7fdf");//点、线的颜色(深色)
        private int mLightColor = Color.parseColor("#d5d8f7");//点、线的颜色(浅色)
        private int mShapeColor = Color.parseColor("#f3f6fd");//阴影的颜色
    
        private String[] mXItems;//X轴的文字
        private int[] mPoints;//点的数组,-1表示该日还没到
        private int mLength = 7;//最大比例
    
        private Paint mDatePaint = new Paint();//日期画笔
        private Paint mPointPaint = new Paint();//点画笔
        private Paint mLinePaint = new Paint();//线条画笔
        private Paint mShapePaint = new Paint();//阴影部分画笔
    
        private int max = 7;
        private Context mContext;
    
        public LineChart(Context context) {
            this(context, null);
        }
    
        public LineChart(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public LineChart(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            TypedArray typedArray = mContext.getTheme().obtainStyledAttributes(attrs, R.styleable.LineChart, 0, 0);
            try {
                mDateTextColor = typedArray.getColor(R.styleable.LineChart_DateTextColor, mDateTextColor);
                mDarkColor = typedArray.getColor(R.styleable.LineChart_DarkColor, mDarkColor);
                mLightColor = typedArray.getColor(R.styleable.LineChart_LightColor, mLightColor);
                mShapeColor = typedArray.getColor(R.styleable.LineChart_ShapeColor, mShapeColor);
                mFontSize = typedArray.getDimensionPixelSize(R.styleable.LineChart_FontSize,
                        (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mFontSize, mContext.getResources().getDisplayMetrics()));
                mStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.LineChart_StrokeWidth,
                        (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mStrokeWidth, mContext.getResources().getDisplayMetrics()));
                mPointRadius = typedArray.getDimensionPixelSize(R.styleable.LineChart_PointRadius,
                        (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPointRadius, mContext.getResources().getDisplayMetrics()));
            } finally {
                typedArray.recycle();
            }
            initPaint();
        }
    
        private void initPaint() {
            //日期画笔
            mDatePaint.setTextSize(mFontSize);
            mDatePaint.setColor(mDateTextColor);
            //点画笔
            mPointPaint.setTextSize(mFontSize);
            mPointPaint.setColor(mDarkColor);
            //先画笔
            mLinePaint.setAntiAlias(true);
            mLinePaint.setStrokeWidth(mStrokeWidth);//设置线条宽度
            mLinePaint.setStyle(Paint.Style.FILL);
            mLinePaint.setColor(mDarkColor);
            //阴影部分画笔
            mShapePaint.setAntiAlias(true);
            mShapePaint.setStyle(Paint.Style.FILL);
            mShapePaint.setColor(mShapeColor);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            mWidth = widthSize;
            mHeight = heightSize;
    //        if (widthMode == MeasureSpec.EXACTLY) {
    //            mWidth = widthSize;
    //        } else if (widthMode == MeasureSpec.AT_MOST) {
    //            mWidth = widthSize;
    //        }
    //
    //        if (heightMode == MeasureSpec.EXACTLY) {
    //            mHeight = heightSize;
    //        } else if (heightMode == MeasureSpec.AT_MOST) {
    //            mHeight = mWidth / 7 * 3;
    //        }
    
            if (heightMode == MeasureSpec.AT_MOST) {
                mHeight = mWidth / 7 * 3;
            }
            setMeasuredDimension(mWidth, mHeight);
        }
    
        private float mAnimatedValue = 0f;
    
        protected void OnAnimationUpdate(ValueAnimator valueAnimator) {
            mAnimatedValue = (float) valueAnimator.getAnimatedValue();
            invalidate();
        }
    
        public ValueAnimator valueAnimator;
    
        private ValueAnimator startViewAnim(float startF, final float endF, long time) {
            valueAnimator = ValueAnimator.ofFloat(startF, endF);
            valueAnimator.setDuration(time);
            valueAnimator.setInterpolator(new LinearInterpolator());
    
    //        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
    
    //        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
    
            valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
    
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    OnAnimationUpdate(valueAnimator);
    
                }
            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
    
                }
    
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                }
    
                @Override
                public void onAnimationRepeat(Animator animation) {
                    super.onAnimationRepeat(animation);
                }
            });
            if (!valueAnimator.isRunning()) {
                valueAnimator.start();
            }
    
            return valueAnimator;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
    
            if (mXItems == null) {
                mXItems = new String[]{"日", "一", "二", "三", "四", "五", "六"};
                mPoints = new int[]{0, -1, -1, -1, -1, -1, -1};
                mLength = mXItems.length;
            }
    
            //最大比例
            for (int i = 0; i < mLength; i++) {
                if (mPoints[i] > max) {
                    max = mPoints[i];
                }
            }
    
            //原点坐标
            int xOrigin = (int) (0.5 * (mWidth / mLength) - mFontSize / 2);
            int yOrigin = (int) (max * ((mHeight - mLength * mFontSize) / max) + 4 * mFontSize);
    
            int[] xPoints = new int[mLength];//x轴的刻度集合
            int[] yPoints = new int[mLength];//y轴的刻度集合
    
            canvas.save();
    
            for (int i = 0; i < mLength; i++) {
    
                //获取点的坐标
                xPoints[i] = (int) ((i + 0.5) * (mWidth / mLength));
                //todo
                yPoints[i] = (int) ((max - (mPoints[i] == -1 ? 0 : mPoints[i]) * mAnimatedValue) * ((mHeight - mLength * mFontSize) / max) + 4 * mFontSize);
    
                if (i > 0) {
                    //画一个实心梯形,阴影部分
                    Path path = new Path();
                    path.moveTo(xPoints[i - 1], yOrigin + mPointRadius / 2);
                    path.lineTo(xPoints[i - 1], yPoints[i - 1]);
                    path.lineTo(xPoints[i], yPoints[i]);
                    path.lineTo(xPoints[i], yOrigin + mPointRadius / 2);
                    path.close();
                    canvas.drawPath(path, mShapePaint);
                }
                //画出日期
                canvas.drawText(mXItems[i], (int) ((i + 0.5) * mWidth / mLength) - mFontSize / 2, mHeight - mFontSize, mDatePaint);
            }
    
            for (int i = 0; i < mLength; i++) {
                if (mPoints[i] == -1) {
                    mLinePaint.setColor(mLightColor);
                    mPointPaint.setColor(mLightColor);
                } else {
                    mLinePaint.setColor(mDarkColor);
                    mPointPaint.setColor(mDarkColor);
                }
                if (i > 0) {
                    //画连线
                    canvas.drawLine(xPoints[i - 1], yPoints[i - 1], xPoints[i], yPoints[i], mLinePaint);
                }
                //画点的数值
                //todo
    
                canvas.drawText(String.valueOf(mPoints[i]).equals("-1") ? " " : new BigDecimal(String.valueOf(mPoints[i] * mAnimatedValue)).setScale(0, BigDecimal.ROUND_HALF_UP) + ""
    //                            String.valueOf(mPoints[i])
                        , xPoints[i] - mFontSize / 4, yPoints[i] - mFontSize, mPointPaint);
            }
    
            for (int i = 0; i < mLength; i++) {
                if (mPoints[i] == -1) {
                    mLinePaint.setColor(mLightColor);
                    mPointPaint.setColor(mLightColor);
                } else {
                    mLinePaint.setColor(mDarkColor);
                    mPointPaint.setColor(mDarkColor);
                }
                //画点
                canvas.drawCircle(xPoints[i], yPoints[i], mPointRadius, mPointPaint);
            }
    
            canvas.restore();
        }
    
        public void setData(List<LineChartData> dataList) {
    
            mLength = dataList.size();
            if (mLength > 0) {
                mXItems = new String[mLength];
                mPoints = new int[mLength];
                for (int i = 0; i < mLength; i++) {
                    mPoints[i] = dataList.get(i).getPoint();
                    mXItems[i] = dataList.get(i).getItem();
                }
            }
            startViewAnim(0f, 1f, 1000);
            invalidate();
        }
    }
    
    源码

    Github - LineChart

    相关文章

      网友评论

          本文标题:自定义view - 折线图

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