Android自定义View折线效果制作

46 篇文章 0 订阅

Android折线效果制作

         前面一段时间工作需要绘制一个折线图效果,但是网上很多框架写的代码都是比较麻烦,又是动画又是点击效果等等,而且还有很多地方的代码看不懂,我觉得还是自己写一个折线图,顺便复习一下这些简单的知识。
         本文绘制简单的折线效果图,并分析折线绘制的实现过程。
效果如图:
z

一.需要的自定义View的基础知识

(一)编写自定义MyView类

1.这个MyView需要继承View。不用解释吧。

2.需要重写两个方法,onSizeChange和onDraw方法,这里是不需要重写onMeasure方法的,因为这个自定义View的视图大小没有发生改变,但是如果需要也是可以重写的。

执行顺序:onMeasure-》onSizeChange—》onDraw
自定义的View中三个最重要的方法解释:
onMeasure可以得到并控制本身和子View的大小
onSizeChange可以得到自身视图View的大小
onDraw绘制视图View的具体实现

(二)绘制的方法API

1.绘制一条直线

canvas.drawLine(x1,y1, x2, y2, mPaint);
说明:前面(x1,y1)代表第一个点的坐标,后面(x2,y2)
代表第二个点的坐标,四个数值就可以生成一条直线,最后一个参数是画笔对象。

2.绘制连续的线

canvas.drawLines(points, mPaint);
说明:points是所有点的数值的数组,4个数值代表一条直线,也就是说points的长度是4的整数倍。

3.绘制文字

canvas.drawText(“心跳的频率”, x, y, mPaint);
说明:第一个参数是要绘制的文字,第二三个参数代表文字绘制开始的左边,第四个参数代表画笔对象。

(三)本文折线的思路分析:

使用的方法主要是canvas.drawLines来绘制连续的线。
这里传人一个集合list的数据都是Y轴方向的分量。

1.X轴方向平分成list.size()段(int dipX=width/list.size()),后一个坐标点的x坐标比前一个坐标增加dipX的长度。

2.Y轴方向平分成若干段(int dipY=height/K),这里K的值根据集合中的最大值来确定,Y轴方向的实际长度是list.get(i)*dipY
3.显示的时候Y的方向和API的是不同的,API中Y是从上往下显示的,而我们实际显示是要从下往上显示。所以原来的Y坐标要变成height-Y(View的高度减去原来的长度)

4.上一条线结束的点的位置就是下一条线的点的起始位置,实现代码:

        float startX = -pointWidth;
            float startY = mHeight - datas.get(0) * pointHeight;
            float stopX, stopY;
            for (int i = 0; i < datas.size(); i++) {

                stopX = startX + pointWidth;     //x轴的坐标每次添加一个单位长度。
                stopY = mHeight - datas.get(i) * pointHeight;
                // 将起点和落点加入集合
                addPoint(points, i, startX, startY, stopX, stopY);
                // 将落点的值记录下来作为下一次的起点
                startX = stopX;
                startY = stopY;
            }

5.这里不要用canvas.drawLine方法来一直绘制直线,这个效率是很低的,要使用canvas.drawLines方法

二.程序设计的代码

(一)自定义的View类LineCharView

package com.example.charview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

/**
 * 折线图
 */

public class LineChartView extends View {

    private int mWidth;
    private int mHeight;


    private List<Integer> mDatas = new ArrayList<Integer>();
    private int paintColors;

    private Paint mPaint;

    public LineChartView(Context context) {
        this(context, null);
    }


    public LineChartView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    /**
     * 设置数据
     *
     * @param datas  集合里面还有每条线的集合数据
     * @param colors 表示线的颜色集合
     */
    public void setDatas(List<Integer> datas, int colors) {

        if (datas != null && datas.size() != 0) {
            mDatas.clear();
            mDatas.addAll(datas);
            paintColors = colors;
            //重绘视图
            postInvalidate();
        }
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStrokeWidth(2f);
        mPaint.setColor(Color.GREEN);
        setBackgroundColor(Color.BLACK);


    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mDatas != null) {  //传人数据后再实现重绘
            mPaint.setColor(paintColors);
            //画底下和顶上的线
            drawBackGroudLines(canvas);


            //画左边的标尺线
            DrawLineLeft(canvas);

            //画下边的标尺线
            drawLineAndTextButtom(canvas);

            //绘制上面的文字提示
            drawTextTop(canvas);
        } else {
            canvas.drawText("正在绘制页面", 100, 100, mPaint);
        }


    }

    /**
     * 绘制底下的横线和文字
     *
     * @param canvas
     */
    private void drawLineAndTextButtom(Canvas canvas) {
        canvas.drawLine(0, mHeight - 50, mWidth, mHeight - 50, mPaint);
        //直线底下的文字
        for (int i = 0; i < 24; i++) {
            String textString = i + ":00";
            mPaint.setTextSize(10);
            canvas.drawText(textString, 40 + i * (mWidth / 24) - 10, mHeight - 30, mPaint);

            //在文字上面画一条小直线
            canvas.drawLine(40 + i * (mWidth / 24), mHeight - 50, 40 + i * (mWidth / 24), mHeight - 70, mPaint);

        }
    }

    /**
     * 绘制左边的坐标线
     *
     * @param canvas
     */
    private void DrawLineLeft(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);//实心
        canvas.drawLine(50, 0, 50, mHeight, mPaint);
        //直线边上的文字
        for (int i = 0; i < 7; i++) {
            String textString = i * 30 + "";
            mPaint.setTextSize(20);
            canvas.drawText(textString, 10, mHeight - i * 30 * (mWidth / 200), mPaint);

        }
    }

    /**
     * 绘制上面的文字提示
     *
     * @param canvas
     */
    private void drawTextTop(Canvas canvas) {
        drawLineChart(canvas, mDatas);
        //画文字
        mPaint.setTextSize(60);
        canvas.drawText("心跳的频率", 50, 50, mPaint);
    }

    /**
     * 传人点的集合数据,绘制线条
     *
     * @param canvas
     * @param datas
     */
    private void drawLineChart(Canvas canvas, List<Integer> datas) {
        int size = datas.size();
        if (size != 0 && size != 1) {
            float[] points = new float[size * 4];
            float pointWidth = (float) mWidth / (float) (size - 1);
            float pointHeight = (float) mHeight / 255f;
            // 起点和落点的 x,y 坐标!
            //Y方向其实是向下偏移了(mHeight-2y)的长度,也就是在原来的基础上添加偏移量的值,即可得到目的的Y
            //比如(x,y)---》(x,mHeight-y)
            //根据API限定距离顶部是y的距离,目的是距离底部是y的距离,而距离顶部是(mHeight-y)的距离,是不是偏移了(mHeight-2y)的长度!
            //  (mHeight-2y)+y= mHeight-y;
            float startX = -pointWidth;
            float startY = mHeight - datas.get(0) * pointHeight;
            float stopX, stopY;
            for (int i = 0; i < datas.size(); i++) {

                stopX = startX + pointWidth;     //x轴的坐标每次添加一个单位长度。
                stopY = mHeight - datas.get(i) * pointHeight;
                // 将起点和落点加入集合
                addPoint(points, i, startX, startY, stopX, stopY);
                // 将落点的值记录下来作为下一次的起点
                startX = stopX;
                startY = stopY;
            }
            canvas.drawLines(points, mPaint);
        }

    }

    /**
     * 将起点和落点加入集合
     *
     * @param points 添加到哪个集合,所有点坐标的最终数组
     * @param i      添加的是哪个点组合的数据,代表的是点的个数
     * @param startX 起点 X 坐标
     * @param startX 起点 Y 坐标
     * @param stopX  落点 X 坐标
     * @param stopY  落点 Y 坐标
     */
    private void addPoint(float[] points, int i, float startX, float startY, float stopX, float stopY) {
        int index = i * 4;
        // 起点
        points[index] = startX;
        points[index + 1] = startY;
        // 落点
        points[index + 2] = stopX;
        points[index + 3] = stopY;
    }

    /**
     * //绘制底部和顶部的线
     */
    private void drawBackGroudLines(Canvas canvas) {
        canvas.drawLine(0, 0, mWidth, 0, mPaint);
        canvas.drawLine(0, mHeight, mWidth, mHeight, mPaint);
    }

    /**
     * 得到View的宽度和高度
     *
     * @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);
        Log.e("TAG2", "onSizeChanged");
        mWidth = getWidth();
        mHeight = getHeight();
    }


}

(二)主方法类调用自定义View

package com.example.charview;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class MyActivity extends Activity {


    /**
     * 自定义折线图的实现
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //数据
        List<Integer> datas = new ArrayList<Integer>();
        datas.add(66);
        datas.add(77);
        datas.add(66);
        datas.add(88);
        datas.add(64);
        datas.add(20);
        datas.add(44);
        datas.add(22);
        datas.add(99);
        datas.add(35);
        datas.add(35);
        datas.add(66);

        LineChartView lineChartView = (LineChartView) findViewById(R.id.lineCharView);
        //给折线图设置数据,和颜色
        lineChartView.setDatas(datas, Color.YELLOW);


    }


    //关闭页面
    public void close(View view) {
        finish();
    }
}

(三)布局文件是非常简单的

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
        >
    <com.example.charview.LineChartView
            android:layout_width="match_parent"
            android:layout_height="400dp"
            android:id="@+id/lineCharView"
            />
    <Button
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:text="关闭"
            android:onClick="close"
            />

</LinearLayout>

运行后效果:

zz

这里的折线图算是很简单的了,使用的方法也是比较简单的,对于初级学习是很有帮助的。
如果想要这个视图可以拉伸可以把它进行处理(photoView的使用):
http://blog.csdn.net/wenzhi20102321/article/details/64919739

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峥嵘life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值