自定义折线图

继续来一片简单的自定义View,折线图的自定义。
这里写图片描述
每天来一篇,进步无极限。愚公移山也要由易到难的,这次就没写xml文件的自定义属性:

 public DefineLineView(Context context) {
        super(context);
    }

    public DefineLineView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DefineLineView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

然后还是重写onMeasure方法:

int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (MeasureSpec.EXACTLY == widthMode) {
            width = widthSize;
        } else {
            throw new IllegalArgumentException("width is exactly mode!");
        }
        if (MeasureSpec.EXACTLY == heightMode) {
            height = heightSize;
        } else {
            throw new IllegalArgumentException("height is exactly mode!");
        }
        setMeasuredDimension(width, height);

由于想省点事,就直接用EXACTLY ,没有去管atmost,无关紧要,
关键在ondraw方法里面比较费事:

@Override
    protected void onDraw(Canvas canvas) {
        Paint mPaint = new Paint();
        mPaint.setTextSize(textFontSize);
        mPaint.setColor(Color.RED);
        /**
         * 画Y轴
         */
        int[] pointY = new int[textY.length];//保存y轴文字的坐标
        //计算每个刻度的间距
        int discY = (int) ((height - textFontSize * textY.length) / textY.length);
        //测量文字的高度
        Paint.FontMetrics fm = mPaint.getFontMetrics();
        int yheight = (int) Math.ceil(fm.descent - fm.ascent);
        for (int i = 0; i < textY.length; i++) {
            canvas.drawText(textY[i], 0, discY * i + yheight, mPaint);
            pointY[i] = discY * i + yheight;
        }
        /**
         * 画X轴
         */
        int[] pointX = new int[textX.length];//保存y轴文字的坐标
        int offset = 50;
        //计算每个刻度的距离
        int discX = (int) ((width - textFontSize * textX.length) / textX.length);
        for (int i = 0; i < textX.length; i++) {
            canvas.drawText(textX[i], i * discX + textFontSize + offset, height - yheight - offset, mPaint);
            pointX[i] = (int) (i * discX + textFontSize + offset);
        }
        /**
         * 画点
         */
        mPaint.setColor(Color.DKGRAY);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        int radious = 10;
        Paint linePaint = new Paint();
        linePaint.setColor(Color.DKGRAY);
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(5);
        for (int i = 0; i < textX.length; i++) {
            if (mapParams == null) {
                throw new IllegalArgumentException("map 不能为空");
            }
            canvas.drawCircle(pointX[i], pointY[mapParams.get(i)], radious, mPaint);
            if (i > 0) {
                canvas.drawLine(pointX[i - 1], pointY[mapParams.get(i - 1)], pointX[i], pointY[mapParams.get(i)], linePaint);
            }
        }
    }

首先画Y轴,在画Y轴的时候定义了一个数组来保存对应的坐标:

  /**
         * 画Y轴
         */
        int[] pointY = new int[textY.length];//保存y轴文字的坐标
        //计算每个刻度的间距
        int discY = (int) ((height - textFontSize * textY.length) / textY.length);
        //测量文字的高度
        Paint.FontMetrics fm = mPaint.getFontMetrics();
        int yheight = (int) Math.ceil(fm.descent - fm.ascent);
        for (int i = 0; i < textY.length; i++) {
            canvas.drawText(textY[i], 0, discY * i + yheight, mPaint);
            pointY[i] = discY * i + yheight;
        }

然后同样画X轴的时候,也要定义一个数组来保存X轴的坐标,

/**
         * 画X轴
         */
        int[] pointX = new int[textX.length];//保存y轴文字的坐标
        int offset = 50;
        //计算每个刻度的距离
        int discX = (int) ((width - textFontSize * textX.length) / textX.length);
        for (int i = 0; i < textX.length; i++) {
            canvas.drawText(textX[i], i * discX + textFontSize + offset, height - yheight - offset, mPaint);
            pointX[i] = (int) (i * discX + textFontSize + offset);
        }

下面就是画点,首先在MainActivity里面定义了一个Map来保存要画的点,通过在View设置的方法把Map传进来。

/**
     * 设置Y轴的数据
     *
     * @param textY
     */
    public void setTextY(String[] textY) {
        this.textY = textY;
    }

    /**
     * 设置X轴的数据
     *
     * @param textX
     */
    public void setTextX(String[] textX) {
        this.textX = textX;
    }

    /**
     * 设置Map
     *
     * @param mapParams
     */
    public void setMapParams(Map<Integer, Integer> mapParams) {
        this.mapParams = mapParams;
    }

然后就开始画点和画折线:

 /**
         * 画点
         */
        mPaint.setColor(Color.DKGRAY);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        int radious = 10;
        Paint linePaint = new Paint();
        linePaint.setColor(Color.DKGRAY);
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(5);
        for (int i = 0; i < textX.length; i++) {
            if (mapParams == null) {
                throw new IllegalArgumentException("map 不能为空");
            }
            canvas.drawCircle(pointX[i], pointY[mapParams.get(i)], radious, mPaint);
            if (i > 0) {
                canvas.drawLine(pointX[i - 1], pointY[mapParams.get(i - 1)], pointX[i], pointY[mapParams.get(i)], linePaint);
            }
        }

最后在MainActivity里面设置下数据就ok了:

  private String[] textY = {"50k", "40k", "30k", "20K", "10k"};
    private String[] textX = {"1", "2", "3", "4", "5", "6", "7"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DefineLineView lineView = (DefineLineView) findViewById(R.id.lineView);

        lineView.setTextY(textY);
        lineView.setTextX(textX);
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < textX.length; i++) {
            map.put(i, (int) (Math.random() * 5));
        }
        lineView.setMapParams(map);
    }

贴一下Xml文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <com.example.shuiai.defineline.DefineLineView
        android:id="@+id/lineView"
        android:layout_width="match_parent"
        android:layout_height="300dp" />
</LinearLayout>

贴下View的完整代码:

public class DefineLineView extends View {
    /**
     * view的宽
     */
    private int width;
    /**
     * View的高
     */
    private int height;
    /**
     * 存放Y轴文字的数组
     */
    private String[] textY;
    /**
     * 存放X轴文字的数组
     */
    private String[] textX;
    /**
     * 文字大小
     */
    private float textFontSize = 40;

    /**
     * 设置Map
     *
     * @param context
     */
    private Map<Integer, Integer> mapParams;

    public DefineLineView(Context context) {
        super(context);
    }

    public DefineLineView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DefineLineView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @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);
        if (MeasureSpec.EXACTLY == widthMode) {
            width = widthSize;
        } else {
            throw new IllegalArgumentException("width is exactly mode!");
        }
        if (MeasureSpec.EXACTLY == heightMode) {
            height = heightSize;
        } else {
            throw new IllegalArgumentException("height is exactly mode!");
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint mPaint = new Paint();
        mPaint.setTextSize(textFontSize);
        mPaint.setColor(Color.RED);
        /**
         * 画Y轴
         */
        int[] pointY = new int[textY.length];//保存y轴文字的坐标
        //计算每个刻度的间距
        int discY = (int) ((height - textFontSize * textY.length) / textY.length);
        //测量文字的高度
        Paint.FontMetrics fm = mPaint.getFontMetrics();
        int yheight = (int) Math.ceil(fm.descent - fm.ascent);
        for (int i = 0; i < textY.length; i++) {
            canvas.drawText(textY[i], 0, discY * i + yheight, mPaint);
            pointY[i] = discY * i + yheight;
        }
        /**
         * 画X轴
         */
        int[] pointX = new int[textX.length];//保存y轴文字的坐标
        int offset = 50;
        //计算每个刻度的距离
        int discX = (int) ((width - textFontSize * textX.length) / textX.length);
        for (int i = 0; i < textX.length; i++) {
            canvas.drawText(textX[i], i * discX + textFontSize + offset, height - yheight - offset, mPaint);
            pointX[i] = (int) (i * discX + textFontSize + offset);
        }
        /**
         * 画点
         */
        mPaint.setColor(Color.DKGRAY);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        int radious = 10;
        Paint linePaint = new Paint();
        linePaint.setColor(Color.DKGRAY);
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(5);
        for (int i = 0; i < textX.length; i++) {
            if (mapParams == null) {
                throw new IllegalArgumentException("map 不能为空");
            }
            canvas.drawCircle(pointX[i], pointY[mapParams.get(i)], radious, mPaint);
            if (i > 0) {
                canvas.drawLine(pointX[i - 1], pointY[mapParams.get(i - 1)], pointX[i], pointY[mapParams.get(i)], linePaint);
            }
        }
    }

    /**
     * 设置Y轴的数据
     *
     * @param textY
     */
    public void setTextY(String[] textY) {
        this.textY = textY;
    }

    /**
     * 设置X轴的数据
     *
     * @param textX
     */
    public void setTextX(String[] textX) {
        this.textX = textX;
    }

    /**
     * 设置Map
     *
     * @param mapParams
     */
    public void setMapParams(Map<Integer, Integer> mapParams) {
        this.mapParams = mapParams;
    }
}

有木有很简单,很简单。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值