android 自定义折线图

在开发中我们需要自定义view的地方很多,我们在开发中需要重写view来实现项目中各式各样的需求,其实自定义view并没有想象中那么难,按照步骤,一步步实现就可以。

这里我实现了一个价格变动折线图,先上图看看效果

这里把实现步骤做一下讲解,

1. 首先创建自己的自定义类,并继承view,然后重写构造方法,使得我们的xml文件可以通过自定义属性实现布局上面的改变;

2. 然后为自定义画笔,测量间距做准备,定义相关变量

//xy坐标轴颜色
    private int xylinecolor = 0xffe2e2e2;
    //xy坐标轴宽度
    private int xylinewidth = dpToPx(1);
    //xy坐标轴文字颜色
    private int xytextcolor = 0xff7e7e7e;
    //xy坐标轴文字大小
    private int xytextsize = spToPx(12);
    //折线图中折线的颜色
    private int linecolor = 0xffff6600;
    //x轴各个坐标点水平间距
    private int interval = dpToPx(50);
    //背景颜色
    private int bgcolor = 0xffffffff;
    //是否在ACTION_UP时,根据速度进行自滑动,没有要求,建议关闭,过于占用GPU
    private boolean isScroll = false;
    //绘制XY轴坐标对应的画笔
    private Paint xyPaint;
    //绘制XY轴的文本对应的画笔
    private Paint xyTextPaint;
    //画折线对应的画笔
    private Paint linePaint;
    private Paint linePaintXu;//虚线画笔
    //画分割线对应的画笔
    private Paint lineVerticalPaint;
    //x轴底线对应的画笔
    private Paint bottomLinePaint;
    //可以渐变的画笔属性
    private LinearGradient lg;
    private int width;
    private int height;
    //x轴的原点坐标
    private int xOri;
    //y轴的原点坐标
    private int yOri;
    //第一个点X的坐标
    private float xInit;
    //第一个点对应的最大Y坐标
    private float maxXInit;
    //第一个点对应的最小X坐标
    private float minXInit;
    private Context context;
    //x轴坐标对应的数据
    private List<String> xValue = new ArrayList<>();
    //y轴坐标对应的数据
    private List<Integer> yValue = new ArrayList<>();
    //折线对应的数据
    private Map<String, Float> value = new HashMap<>();
    //点击的点对应的X轴的第几个点,默认1
    private int selectIndex = 0;
    //X轴刻度文本对应的最大矩形,为了选中时,在x轴文本画的框框大小一致
    private Rect xValueRect;
    //速度检测器
    private VelocityTracker velocityTracker;

3. 做初始化操作,xml文件自定义属性的初始化,画笔的初始化

   /**
     * 初始化
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.chartView, defStyleAttr, 0);
        int count = array.getIndexCount();
        for (int i = 0; i < count; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.chartView_xylinecolor://xy坐标轴颜色
                    xylinecolor = array.getColor(attr, xylinecolor);
                    break;
                case R.styleable.chartView_xylinewidth://xy坐标轴宽度
                    xylinewidth = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xylinewidth, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.chartView_xytextcolor://xy坐标轴文字颜色
                    xytextcolor = array.getColor(attr, xytextcolor);
                    break;
                case R.styleable.chartView_xytextsize://xy坐标轴文字大小
                    xytextsize = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xytextsize, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.chartView_linecolor://折线图中折线的颜色
                    linecolor = array.getColor(attr, linecolor);
                    break;
                case R.styleable.chartView_interval://x轴各个坐标点水平间距
                    interval = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, interval, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.chartView_bgcolor: //背景颜色
                    bgcolor = array.getColor(attr, bgcolor);
                    break;
                case R.styleable.chartView_isScroll://是否在ACTION_UP时,根据速度进行自滑动
                    isScroll = array.getBoolean(attr, isScroll);
                    break;
            }
        }
        array.recycle();

    }
  /**
     * 初始化画笔
     */
    private void initPaint() {
        xyPaint = new Paint();
        xyPaint.setAntiAlias(true);
        xyPaint.setStrokeWidth(xylinewidth);
        xyPaint.setStrokeCap(Paint.Cap.ROUND);
        xyPaint.setColor(xylinecolor);

        xyTextPaint = new Paint();
        xyTextPaint.setAntiAlias(true);
        xyTextPaint.setTextSize(xytextsize);
        xyTextPaint.setStrokeCap(Paint.Cap.ROUND);
        xyTextPaint.setColor(xytextcolor);
        xyTextPaint.setStyle(Paint.Style.STROKE);

        linePaint = new Paint();
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(xylinewidth);
        linePaint.setStrokeCap(Paint.Cap.ROUND);
        linePaint.setColor(linecolor);
        linePaint.setStyle(Paint.Style.STROKE);

        linePaintXu = new Paint();
        linePaintXu.setAntiAlias(true);
        linePaintXu.setStrokeWidth(xylinewidth);
        linePaintXu.setColor(linecolor);
        linePaintXu.setStyle(Paint.Style.STROKE);

        lineVerticalPaint = new Paint();
        lineVerticalPaint.setAntiAlias(true);
        lineVerticalPaint.setStyle(Paint.Style.FILL);

        bottomLinePaint = new Paint();
        bottomLinePaint.setAntiAlias(true);
        bottomLinePaint.setStrokeWidth(xylinewidth);
        bottomLinePaint.setStrokeCap(Paint.Cap.ROUND);
        bottomLinePaint.setColor(0xffffe7d6);
        bottomLinePaint.setStyle(Paint.Style.STROKE);

    }

4. 实现onlayout,onmeasure,ondraw方法,通过测量,确定布局区域,绘制出折线图,这里需要确定各个位置的描点,首先是xy轴的坐标点,然后就是折线图趋势走势的点,然后就是绘制textview给予文本提示,思路大致是这样,然后就是代码实现了

类似于图表的在github上面有开源的第三方框架,用起来也是比较方便,自定义这个图标只是为了练习下自定义view,锻炼动手能力,熟悉自定义view的一般过程,当然有时候也需要view跟随手势变化做重绘,自定义view要注意内存的优化,不要发生内存抖动,更要避免发生OOM。

完整代码github链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值