Android 自定义折线图

先上图
在这里插入图片描述分析
在这里插入图片描述

x轴

x轴起始x坐标 = 原点x坐标
x轴起始y坐标 = 原点y坐标
x轴终止x坐标 = 原点x坐标 + x轴长度 + j
x轴终止y坐标 = 原点y坐标

代码

canvas.drawLine(mXPoint,mYPoint,mXLength + mXPoint + 20,mYPoint,mainPaint);
x轴刻度

可以根据传入数据的量循环画刻度

线条 a 起始x坐标 = 原点x坐标 + 循环数 × x轴刻度长度
线条 a 起始y坐标 = 原点y坐标
线条 a 终止x坐标 = 原点x坐标 + 循环数 × x轴刻度长度
线条 a 终止y坐标 = 原点y坐标 - 5 (5 是刻度的高度,可以自己设置)

线条 a 刻度文字x坐标 = 原点x坐标 + 循环数 × x轴刻度长度
线条 a 刻度文字y坐标 = 原点y坐标 +15(15 是文字向下移动的距离,可以自己设置)

代码

for (int i=0;i<mXAxialScale.length;i++){
    canvas.drawLine(mXPoint + i * mXScale,mYPoint,mXPoint + i * mXScale,mYPoint-5,mainPaint);
    canvas.drawText(mXAxialScale[i],mXPoint + i * mXScale,mYPoint + 15,textPaint);
}
x轴最后的箭头

上箭头
起始x坐标 = 原点x坐标 + x轴长度 + j
起始y坐标 = 原点y坐标
终止x坐标 = 原点x坐标 + x轴长度 + 15(个人设置为15,可以自己设置)
终止y坐标 = 原点y坐标 - 5(个人设置为5,可以自己设置)

下箭头
起始x坐标 = 原点x坐标 + x轴长度 + j
起始y坐标 = 原点y坐标
终止x坐标 = 原点x坐标 + x轴长度 + 15(个人设置为15,可以自己设置)
终止y坐标 = 原点y坐标 + 5(个人设置为5,可以自己设置)

代码

 //x上箭头
canvas.drawLine(mXLength + mXPoint + 20,mYPoint,mXLength + mXPoint + 15,mYPoint - 5,mainPaint);
//x下箭头
canvas.drawLine(mXLength + mXPoint + 20,mYPoint,mXPoint + mXLength + 15,mYPoint + 5,mainPaint);

y轴

y轴起始x坐标 = 原点x坐标
y轴起始y坐标 = 原点y坐标
y轴终止x坐标 = 原点x坐标
y轴终止y坐标 = 原点y坐标 - y轴长度 - i

代码

canvas.drawLine(mXPoint,mYPoint,mXPoint,mYPoint-mYLength-20,mainPaint);
y轴刻度

和x轴差不多,根据传入数据的量循环画即可

线条 b 起始x坐标 = 原点x坐标
线条 b 起始y坐标 = 原点y坐标 - 循环数 × y轴刻度长度
线条 b 终止x坐标 = 原点x坐标 + 5(5 是刻度的宽度,可以自己设置)
线条 b 终止y坐标 = 原点y坐标 - 循环数 × y轴刻度长度

线条 b 刻度文字x坐标 = 原点x坐标 - 20(20 是文字向左移动的距离,可以自己设置)
线条 b 刻度文字y坐标 = 原点y坐标 - 循环数 × y轴刻度长度

代码

for (int i=0;i<mYAxialScale.length;i++){
    canvas.drawLine(mXPoint,mYPoint - i * mYScale,mXPoint + 5,mYPoint - i * mYScale,mainPaint);
    canvas.drawText(mYAxialScale[i],mXPoint - 20,mYPoint - i * mYScale,textPaint);
}
y轴上面的箭头

左箭头
起始x坐标 = 原点x坐标
起始y坐标 = 原点y坐标 - y轴长度 - i
终止x坐标 = 原点x坐标 - 5(个人设置为5,可以自己设置)
终止y坐标 = 原点y坐标 - y轴长度 - 15(个人设置为15,可以自己设置)

右箭头
起始x坐标 = 原点x坐标
起始y坐标 = 原点y坐标 - y轴长度 - i
终止x坐标 = 原点x坐标 + 5(个人设置为5,可以自己设置)
终止y坐标 = 原点y坐标 - y轴长度 - 15(个人设置为15,可以自己设置)

代码

//y左箭头
canvas.drawLine(mXPoint,mYPoint - mYLength - 20,mXPoint - 5,mYPoint - mYLength - 15,mainPaint);
//y右箭头
canvas.drawLine(mXPoint,mYPoint - mYLength - 20,mXPoint + 5,mYPoint - mYLength - 15,mainPaint);

画标题

位置随意,不超出屏幕,不遮挡数据就行…
代码

canvas.drawText(mTitle, (mXPoint+mXLength+100)/2, mYPoint+100, textPaint);

画点、点与点之间的折线

循环画即可,直接上代码

        for (int i=0;i<mData.length;i++){
            if (i>0){
                //原点坐标+第一个刻度,y坐标,原点+第二个刻度,y坐标
                canvas.drawLine(mXPoint + (i - 1) * mXScale,getY(mData[i - 1]),mXPoint + i * mXScale,getY(mData[i]),mainPaint);
            }
            //画点
            canvas.drawCircle(mXPoint + i * mXScale,getY(mData[i]),5,pointPaint);
            canvas.drawText(mData[i],mXPoint +  i * mXScale+10,getY(mData[i]),indexPaint);
        }
获取折线的y坐标
    private float getY(String y){
        return mYPoint - Float.valueOf(y) * mYScale / mStep;
    }

坐标原点可以自己设置,y轴和x轴长度也可以自己设置,只要不超过手机屏幕宽度和高度就可以

x轴和y轴刻长度可以设置为固定值,也可以通过传入数据的数量动态设置,但如果数量过多,刻度与刻度之间会比较拥挤,其他就是上面的内容了

全部代码

AndroidManifest.xml 设置横屏

        <activity android:name=".MainActivity"
            android:screenOrientation="landscape">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

自定义布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.iot.nss.customchart.ChartView
        android:id="@+id/chart_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/update_btn"
        android:layout_alignParentRight="true"
        android:text="更新数据"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

ChartView.java

public class ChartView extends View {
    private Paint mainPaint;//主画笔
    private Paint pointPaint;//点
    private Paint indexPaint;//坐标
    private Paint textPaint;//文字

    private int mXPoint = 150;//原点X轴坐标
    private int mYPoint = 700;//原点Y轴坐标
    private int mXScale;//X轴刻度长度
    private int mYScale;//Y轴刻度长度
    private int mXLength;//X轴长度
    private int mYLength;//Y轴长度

    private String[] mXAxialScale;//X轴刻度值
    private String[] mYAxialScale;//Y轴刻度值
    private String[] mData;//数据
    private String mTitle;//标题
    private int mStep;//y轴步增值

    public void setInfo(String[] mXAxialScale, String[] mYAxialScale,String strTitle,int mStep) {
        this.mXAxialScale = mXAxialScale;//横坐标
        this.mYAxialScale = mYAxialScale;//纵坐标
        this.mTitle = strTitle;
        this.mStep = mStep;
    }

    public void setData(String[]data){
        this.mData = data;
        postInvalidate();//更新
    }

	//一定要写这个构造不然会报错  这个构造会在创建控件时自动调用
    public ChartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

    private void initPaint() {
        mainPaint = new Paint();
        mainPaint.setStrokeWidth(2);//线宽
        mainPaint.setAntiAlias(true);//去锯齿
        mainPaint.setColor(Color.DKGRAY);//颜色
        mainPaint.setTextSize(12);

        //文字
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setColor(Color.DKGRAY);
        textPaint.setTextSize(12);

        //坐标
        indexPaint = new Paint();
        indexPaint.setAntiAlias(true);
        indexPaint.setColor(Color.RED);
        indexPaint.setTextSize(12);

        //点
        pointPaint = new Paint();
        pointPaint.setAntiAlias(true);
        pointPaint.setStyle(Paint.Style.FILL);//实心
        textPaint.setTextSize(16);
    }

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

        getXScale();


        //画x
        canvas.drawLine(mXPoint,mYPoint,mXLength + mXPoint + 20,mYPoint,mainPaint);
        //显示刻度
        for (int i=0;i<mXAxialScale.length;i++){
            canvas.drawLine(mXPoint + i * mXScale,mYPoint,mXPoint + i * mXScale,mYPoint-5,mainPaint);
            canvas.drawText(mXAxialScale[i],mXPoint + i * mXScale,mYPoint + 15,textPaint);
        }
        //x上箭头
        canvas.drawLine(mXLength + mXPoint + 20,mYPoint,mXLength + mXPoint + 15,mYPoint - 5,mainPaint);
        //x下箭头
        canvas.drawLine(mXLength + mXPoint + 20,mYPoint,mXPoint + mXLength + 15,mYPoint + 5,mainPaint);

        //画y
        canvas.drawLine(mXPoint,mYPoint,mXPoint,mYPoint-mYLength-20,mainPaint);
        //显示刻度
        for (int i=0;i<mYAxialScale.length;i++){
            canvas.drawLine(mXPoint,mYPoint - i * mYScale,mXPoint + 5,mYPoint - i * mYScale,mainPaint);
            canvas.drawText(mYAxialScale[i],mXPoint - 20,mYPoint - i * mYScale,textPaint);
        }
        //y左箭头
        canvas.drawLine(mXPoint,mYPoint - mYLength - 20,mXPoint - 5,mYPoint - mYLength - 15,mainPaint);
        //y右箭头
        canvas.drawLine(mXPoint,mYPoint - mYLength - 20,mXPoint + 5,mYPoint - mYLength - 15,mainPaint);

        //折线
        for (int i=0;i<mData.length;i++){
            if (i>0){
                //原点坐标+第一个刻度,y坐标,原点+第二个刻度,y坐标
                canvas.drawLine(mXPoint + (i - 1) * mXScale,getY(mData[i - 1]),mXPoint + i * mXScale,getY(mData[i]),mainPaint);
            }
            //画点
            canvas.drawCircle(mXPoint + i * mXScale,getY(mData[i]),5,pointPaint);
            canvas.drawText(mData[i],mXPoint +  i * mXScale+10,getY(mData[i]),indexPaint);
        }

        //设置标题
        canvas.drawText(mTitle, (mXPoint + mXLength + 100)/2, mYPoint + 100, textPaint);
    }

    //获取y坐标
    private float getY(String y){
        return mYPoint - Float.valueOf(y) * mYScale / mStep;
    }

    //设置x和y轴长度以及刻度长度
    private void getXScale(){
        mXLength = getWidth() - 200;
        mYLength = getHeight() - 400;
        mXScale = mXLength/(mXAxialScale.length - 1);
        mYScale = mYLength/(mYAxialScale.length - 1);
    }
}

主界面使用

    private ChartView chartView;

    private String[] xScale = {"0","1","2","3","4","5","6","7","8","9"};
    private String[] yScale = {"0", "2", "4", "6", "8", "10", "12", "14", "16", "18", "20"};
    private String[] data = new String[10];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        chartView = findViewById(R.id.chart_view);
        Button updateBtn = findViewById(R.id.update_btn);
        chartView.setInfo(xScale,yScale,"测试",2);
        updateData();
        updateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                updateData();
            }
        });
    }

    private void updateData(){
        for (int i=0;i<data.length;i++){
            data[i] = String.valueOf(new Random().nextInt(20));
        }
        chartView.setData(data);
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值