自定义view——折线图

安卓开发,自定义view折线图的练习

效果图
这里写图片描述

1.自定义view

public class BrokenLineView extends View {
    private float left;//折线图左边坐标
    private float bottom;//折线图底部坐标
    private float right;//折线图右边坐标
    private float top;//折线图顶部坐标


    private Context context;
    private Canvas mCanvas;
    private Path mPath;
    private Paint linePaint;
    private Paint mTextPaint;
    public BrokenLineView(Context context) {
        super(context);
    }

    public BrokenLineView(Context context, AttributeSet attrs) {
        super(context, attrs);

        this.context = context;
        initPaint();
        initData();
    }

    private void initPaint(){
        mPath = new Path();
        linePaint = new Paint();
        linePaint.setColor(Color.YELLOW);//线条的颜色
        linePaint.setStrokeWidth(8);//线条的宽度
        linePaint.setAntiAlias(true);//取消锯齿
        linePaint.setStyle(Paint.Style.STROKE);//粗线
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG);
        mTextPaint.setColor(Color.WHITE);
        mCanvas = new Canvas();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();//锁定画布
        drawXY(canvas);
        drawXYelement(canvas);
        drawLines(canvas);
        drawBitmap(canvas);
    }

    /**
     * 获取父控件尺寸
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        left = w*(1/16f);
        right = w*(15/16f);
        top = w*(1/16f);
        bottom = w*(8/16f);
    }


    //画XY坐标轴
    private void drawXY(Canvas canvas){

        /**
         * 连接三个坐标点
         * 1(left,top) 2(left,bottom) 3(right,bottom)
         */
        Log.i("123", "left: "+left+"top: "+top+"bottom: "+bottom);
        mPath.moveTo(left,top);
        mPath.lineTo(left,bottom);
        mPath.lineTo(right,bottom);

        //连接三个坐标
        canvas.drawPath(mPath,linePaint);
        //释放画布
        canvas.restore();
    }

    //画坐标轴旁边的XY
    private void drawXYelement(Canvas canvas){
        canvas.save();

        mTextPaint.setTextSize(36);//文字大小

        //Y轴文字提示
        mTextPaint.setTextAlign(Paint.Align.LEFT);
        canvas.drawText("Y",left+20,top,mTextPaint);

        //X轴文字提示
        mTextPaint.setTextAlign(Paint.Align.RIGHT);
        canvas.drawText("X",right,bottom+50,mTextPaint);

        canvas.restore();
    }

    private List<PointF> pointFList = new ArrayList<>();
    private String[] index_x = {"","周一","周二","周三","周四","周五","周六","周天"};
    private int[] index_y = {0,1,2,3,4,5,6,7,8};
    private float spaceX,spaceY;//横纵坐标间隔
    private float maxX,maxY;//横纵数据最大值
    private void initData(){
        pointFList.add(new PointF(0.3F, 0.5F));
        pointFList.add(new PointF(1F, 22.7F));
        pointFList.add(new PointF(2F, 33.5F));
        pointFList.add(new PointF(3F, 36.2F));
        pointFList.add(new PointF(4F, 18.8F));
        pointFList.add(new PointF(5F, 15.5F));
        pointFList.add(new PointF(6F, 24.2F));
        pointFList.add(new PointF(7F, 52.5F));
    }
    //画网格
    private void drawLines(Canvas canvas){
        canvas.save();
        linePaint.setStrokeWidth(2);

        int count = pointFList.size();
        spaceX = (right-left)/count;
        spaceY = (bottom-top)/count;
        // 计算除数的值为数据长度减一,8个数据,7条线。
        int divisor = count-1;

        //计算X轴最大值
        for (int i = 0; i < count; i++) {
            if (maxX<pointFList.get(i).x){
                maxX = pointFList.get(i).x;//X轴最大值
            }
        }
        //计算X轴最近的能被Count整除的值
        int remainderX = (int) maxX % divisor;
        maxX = remainderX == 0 ? ((int) maxX) : divisor - remainderX + maxX;

        //计算Y轴最大值
        for (int i = 0; i < count; i++) {
            if (maxY < pointFList.get(i).y){
                maxY = pointFList.get(i).y;//y轴最大值
            }
        }
        //计算Y轴最近的能被count整除的值
        int remainderY = ((int) maxY) % divisor;
        maxY = remainderY == 0 ? ((int) maxY) : divisor + remainderY + maxY;

        //锁定画布并设定透明度为75%
        int sc = canvas.saveLayerAlpha(0,0,canvas.getWidth(),canvas.getHeight(),75,Canvas.ALL_SAVE_FLAG);
        // 绘制横纵线段
        for (float y = bottom - spaceY; y >  top; y -= spaceY) {

            for (float x =  left; x < right; x += spaceX) {
                /*
                 * 绘制纵向线段
                 */
                if (y == top + spaceY) {
                    canvas.drawLine(x, y, x, y + spaceY * (count - 1), linePaint);
                }

                /*
                 * 绘制横向线段
                 */
                if (x == right - spaceX) {
                    canvas.drawLine(x, y, x - spaceX * (count - 1), y, linePaint);
                }
            }
        }
        //还原画布
        canvas.restoreToCount(sc);
        int num = 0;//用于给X轴赋值
        int num_y  = 0;//用于给Y轴赋值

        for (float y = bottom - spaceY; y > top; y -= spaceY) {
            for (float x = left; x < right; x += spaceX) {
                mTextPaint.setTextSize(28);

                /*
                 * 绘制横轴刻度数值
                 */
                if (y == bottom - spaceY) {
                    canvas.drawText(""+index_x[num], x+8, bottom+top/2, mTextPaint);
                }

                /*
                 * 绘制纵轴刻度数值
                 * 简单来说就是,Y轴上的坐标点,X轴是恒定不变的,但是Y轴是变化的(buttom - 间距)+10的距离向上绘制
                 */
                if (x == left) {
                    canvas.drawText(""+index_y[num_y+1], left - (left/2), y + 10, mTextPaint);
                }
                num++;
            }
            num_y++;
        }
    }

    private void drawBitmap(Canvas canvas){
        /**
         * 我们给我们的区域先绘制一个颜色模块,做法很简单,生成一个图片即可,然后透明度设置下
         * Bitmap.createBitmap()
         * 关于他的6个方法,可查看博客:http://www.cnblogs.com/wangxiuheng/p/4503610.html
         */
        Log.i("123", "X: "+((int) (right - left - spaceX))+";Y:"+((int) (bottom - top - spaceY)));
        Bitmap bitmap = Bitmap.createBitmap(((int) (right - left - spaceX)), ((int) (bottom - top - spaceY)), Bitmap.Config.ARGB_8888);
        mCanvas.setBitmap(bitmap);
        /**
         * 为画布填充一个半透明的红色
         * drawARGB(a,r,g,b)a:透明度 r:红色g:绿色b:蓝色
         * */
        mCanvas.drawARGB(55,255,0,0);
        mPath.reset();//重置曲线
        canvas.drawBitmap(bitmap,left,top+spaceY,null);


        //绘制我们的坐标点
        drawText(canvas);
    }


    public synchronized void setdata(List<PointF> mList, String signX, String signY, Activity activity){
        if (null == mList || mList.size() == 0){
            throw new IllegalArgumentException("没有数据展示");
        }
        if (mList.size()>10){
            throw new IllegalArgumentException("数据太多建议使用散点图");
        }

        //设置数据并重绘视图
        this.pointFList = mList;
        this.context = activity;

        invalidate();

    }

    private void drawText(Canvas canvas) {
        Paint pointPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        pointPaint.setStyle(Paint.Style.FILL);//焦点的类型
        pointPaint.setColor(Color.WHITE);//焦点的颜色

        if(pointFList.size()==0){
            Toast.makeText(context,"暂无折现数据",Toast.LENGTH_SHORT).show();
        }else {
                /*
         * 生成Path和绘制Point
         */
            for (int i = 0; i < pointFList.size(); i++) {
                // 计算x坐标
                float x = mCanvas.getWidth() / maxX * pointFList.get(i).x;
                // 计算y坐标
                float y = mCanvas.getHeight() / maxY * pointFList.get(i).y;
                y = mCanvas.getHeight() - y;

                // 绘制小点点
                mCanvas.drawCircle(x, y, 6, pointPaint);

            /*
             * 如果是第一个点则将其设置为Path的起点
             */
                if (i == 0) {
                    mPath.moveTo(x, y);
                }

                // 连接各点
                mPath.lineTo(x, y);
            }

            // 设置PathEffect
            linePaint.setPathEffect(new CornerPathEffect(10));

            // 重置线条宽度
            linePaint.setStrokeWidth(4);

            // 将Path绘制到我们自定的Canvas上
            mCanvas.drawPath(mPath, linePaint);
        }
    }
}

2.xml中引用

    <com.hsg.brokenlinedemo.BrokenLineView
        android:id="@+id/blv"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        android:background="#8B7500"/>

3.activity中添加数据

        List<PointF> pointFs = new ArrayList<PointF>();
        pointFs.add(new PointF(0.3F, 0.5F));
        pointFs.add(new PointF(1F, 22.7F));
        pointFs.add(new PointF(2F, 33.5F));
        pointFs.add(new PointF(3F, 36.2F));
        pointFs.add(new PointF(4F, 18.8F));
        pointFs.add(new PointF(5F, 15.5F));
        pointFs.add(new PointF(6F, 24.2F));
        pointFs.add(new PointF(7F, 52.5F));

        blv.setdata(pointFs, "X轴提示文字", "Y轴提示文字",MainActivity.this);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值