android绘制曲线和折线图的方法

本文实例为大家分享了android绘制曲线和折线图的具体代码,供大家参考,具体内容如下

(曲线)

(折线)

1.CurveView.java

package com.package;
 
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Pair;
import android.util.TypedValue;
import android.view.View;
import android.view.WindowManager;
 
import androidx.annotation.Nullable;
 
import java.util.ArrayList;
import java.util.List;
 
public class CurveView extends View {
    private Paint mBrokenLinePaint;
    private Paint mInCirclePaint;
    private Paint mFillCirclePaint;
    private Paint mOutCirclePaint;
    private Paint mBottomLinePaint;
    private Paint mXTextPaint;
    private Paint mYLinePaint;
    private Paint mYTextPaint;
    private boolean isCurve;
    /**
     * X轴的数量,按需调整
     */
    private int mLength = 7;
    /**
     * 获取屏幕的宽度
     */
    private final int mScreenWidth = getScreenWidth(getContext());
    /**
     * 获取实际屏幕的宽度
     */
    private int cScreenWidth = getScreenWidth(getContext());
    /**
     * 整个折线图的高度=屏幕高度-顶部的状态栏高度
     */
    private final int mHeight = getScreenHeight(getContext()) - dp2px(getContext(), 190);
    /**
     * 节点外圆的半径
     */
    private final int outRadius = dp2px(getContext(), 6);
    /**
     * 节点内圆的半径
     */
    private final int inRadius = dp2px(getContext(), 3);
    /**
     * 左右两边距边缘的距离
     */
    private final float mSideLength = dp2px(getContext(), 20);
    /**
     * X轴底部文字的高度
     */
    private final int mXTextHeight = dp2px(getContext(), 30);
 
    /**
     * 距离上边距的高度
     */
    private final int mPaddingTop = dp2px(getContext(), 10);
 
    /**
     * 获取间隔距离
     */
    private int mSpaceLength;
    /**
     * 用户设置的数据
     */
    private final List<Pair<String, Float>> dataValue = new ArrayList<>();
    /**
     * 节点数据
     */
    private final List<Pair<Float, Float>> nodeValue = new ArrayList<>();
    /**
     * 节点上标注的文字
     */
    private final List<String> yValue = new ArrayList<>();
    private Paint mShadowPaint;
 
    public CurveView(Context context) {
        this(context, null);
    }
 
    public CurveView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
 
    public CurveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
 
    /**
     * dp转px
     */
    public static int dp2px(Context context, float dp) {
        float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
        return Math.round(px);
    }
 
    /**
     * 获取屏幕宽度
     */
    public static int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Point size = new Point();
        wm.getDefaultDisplay().getSize(size);
        return size.x;
    }
 
    /*设置实际内容宽度*/
    public void setContentWidth(int size) {
        mLength = size + 1;
        cScreenWidth = (mScreenWidth / 7) * size;
    }
 
    /**
     * 获取屏幕高度
     */
    public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Point size = new Point();
        wm.getDefaultDisplay().getSize(size);
        return size.y;
    }
 
    /**
     * 设置数据
     */
    public void setData(List<String> xAxis, List<String> yAxis) {
        dataValue.clear();
        yValue.clear();
        float yHeight = mHeight - mXTextHeight;
        for (int i = 0; i < xAxis.size(); i++) {
            yValue.add(yAxis.get(i));
            float value = Float.parseFloat(yAxis.get(i));
            dataValue.add(new Pair<>(xAxis.get(i), (yHeight - value / 200f * yHeight)));
        }
        invalidate();
        requestLayout();
    }
 
    private void init() {
        getSpaceLength();//获取间隔距离
        initYLine();//初始化竖直方向的线条
        initBottomLine();//初始化底部横线paint
        initInCircle();//初始化节点内圆
        initBrokenLine();//初始化曲线、折线
        initXtext();//初始化X轴标签
        initYtext();//初始化Y轴上数值
        initShadowPaint();//初始化阴影
    }
 
    /**
     * 获取间隔距离
     * (屏幕宽度-两边的间距)/(x轴数量-1)
     */
    private void getSpaceLength() {
        mSpaceLength = (int) (mScreenWidth - mSideLength * 2) / (mLength - 1);
    }
 
    /**
     * 初始化竖直方向的线条
     */
    private void initYLine() {
        mYLinePaint = new Paint();
        mYLinePaint.setColor(Color.GRAY);
        mYLinePaint.setStrokeWidth(1);
        mYLinePaint.setStyle(Paint.Style.STROKE);
        mYLinePaint.setAntiAlias(true);
    }
 
    /**
     * 初始化底部横线paint
     */
    private void initBottomLine() {
        mBottomLinePaint = new Paint();
        mBottomLinePaint.setColor(Color.GRAY);
        mBottomLinePaint.setStrokeWidth(dp2px(getContext(), 0.5f));
        mBottomLinePaint.setStyle(Paint.Style.STROKE);
        mBottomLinePaint.setAntiAlias(true);
    }
 
    /**
     * 初始化X轴标签
     */
    private void initXtext() {
        mXTextPaint = new Paint();
        mXTextPaint.setColor(Color.GRAY);
        mXTextPaint.setTextSize(dp2px(getContext(), 12));
        mXTextPaint.setStyle(Paint.Style.FILL);
        mXTextPaint.setAntiAlias(true);
    }
 
    /**
     * 初始化Y轴上数值
     */
    private void initYtext() {
        mYTextPaint = new Paint();
        mYTextPaint.setColor(Color.GRAY);
        mYTextPaint.setTextSize(dp2px(getContext(), 12));
        mYTextPaint.setStyle(Paint.Style.FILL);
        mYTextPaint.setAntiAlias(true);
    }
 
    /**
     * 初始化节点内圆
     */
    private void initInCircle() {
        //初始化外圆
        mOutCirclePaint = new Paint();
        mOutCirclePaint.setColor(Color.GREEN);
        mOutCirclePaint.setStyle(Paint.Style.FILL);
        mOutCirclePaint.setAntiAlias(true);
        //内框
        mInCirclePaint = new Paint();
        mInCirclePaint.setColor(Color.GRAY);
        mInCirclePaint.setStyle(Paint.Style.STROKE);
        mInCirclePaint.setStrokeWidth(dp2px(getContext(), 2));
        mInCirclePaint.setAntiAlias(true);
        //内圆
        mFillCirclePaint = new Paint();
        mFillCirclePaint.setColor(Color.GRAY);
        mFillCirclePaint.setStyle(Paint.Style.FILL);
        mFillCirclePaint.setAntiAlias(true);
    }
 
    /**
     * 初始化曲线、折线
     */
    private void initBrokenLine() {
        mBrokenLinePaint = new Paint();//折线
        mBrokenLinePaint.setColor(Color.GRAY);
        mBrokenLinePaint.setStrokeWidth(dp2px(getContext(), 2f));
        mBrokenLinePaint.setStyle(Paint.Style.STROKE);
        mBrokenLinePaint.setStrokeCap(Paint.Cap.ROUND);
        mBrokenLinePaint.setAntiAlias(true);
    }
 
    /**
     * 初始化阴影
     */
    private void initShadowPaint() {
        mShadowPaint = new Paint();
        mShadowPaint.setStyle(Paint.Style.FILL);
        mShadowPaint.setAntiAlias(true);
        Shader shader = new LinearGradient(getWidth() / 2f, getHeight(), getWidth() / 2f, 0,
                Color.parseColor("#3300FF00"), Color.parseColor("#3300FF00"), Shader.TileMode.MIRROR);
        mShadowPaint.setShader(shader);
    }
 
    /**
     * 绘制
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawYLine(canvas);
        // 绘制底部的X轴线
        drawBottomLine(canvas);
        // 绘制节点和折线图
        drawCircleLine(canvas);
        // 绘制Y轴上的数据和背景
        drawYtext(canvas);
        // 绘制X轴标签文字
        drawBottomText(canvas);
        //阴影
        drawShadow(canvas);
    }
 
    /**
     * 绘制竖直方向上的线
     */
    private void drawYLine(Canvas canvas) {
        for (int i = 0; i < dataValue.size(); i++) {
            canvas.drawLine(mSideLength + mSpaceLength * i, mPaddingTop, mSideLength + mSpaceLength * i, mHeight - mXTextHeight, mYLinePaint);
        }
    }
 
    /**
     * 绘制节点和曲线或者折线图
     */
    private void drawCircleLine(Canvas canvas) {
        nodeValue.clear();
        for (int i = 0; i < dataValue.size(); i++) {
            Pair<String, Float> pair = dataValue.get(i);
            // 绘制节点外圆
            canvas.drawCircle(mSideLength + mSpaceLength * i, pair.second, outRadius, mOutCirclePaint);
            // 绘制节点内框
            canvas.drawCircle(mSideLength + mSpaceLength * i, pair.second, inRadius, mFillCirclePaint);
            // 绘制节点内圆
            canvas.drawCircle(mSideLength + mSpaceLength * i, pair.second, inRadius, mInCirclePaint);
            // 保存圆心坐标
            Pair<Float, Float> pairs = new Pair<>(mSideLength + mSpaceLength * i, pair.second);
            nodeValue.add(pairs);
        }
        drawScrollLine(canvas);//曲线
        // drawLine(canvas);//折线
    }
 
    /**
     * 绘制曲线图
     */
    private void drawScrollLine(Canvas canvas) {
        isCurve = true;
        PointF pStart, pEnd;
        List<PointF> points = getPoints();
        Path path = new Path();
        for (int i = 0; i < points.size() - 1; i++) {
            pStart = points.get(i);
            pEnd = points.get(i + 1);
            PointF point3 = new PointF();
            PointF point4 = new PointF();
            float wd = (pStart.x + pEnd.x) / 2;
            point3.x = wd;
            point3.y = pStart.y;
            point4.x = wd;
            point4.y = pEnd.y;
            path.moveTo(pStart.x, pStart.y);
            path.cubicTo(point3.x, point3.y, point4.x, point4.y, pEnd.x, pEnd.y);
            canvas.drawPath(path, mBrokenLinePaint);
        }
    }
 
    /**
     * 绘制折线
     */
    private void drawLine(Canvas canvas) {
        isCurve = false;
        for (int i = 0; i < nodeValue.size(); i++) {
            if (i != nodeValue.size() - 1) {
                canvas.drawLine((float) nodeValue.get(i).first,
                        (float) nodeValue.get(i).second,
                        (float) nodeValue.get(i + 1).first,
                        (float) nodeValue.get(i + 1).second, mBrokenLinePaint);
            }
        }
    }
 
    /**
     * 绘制阴影
     */
    private void drawShadow(Canvas canvas) {
        List<PointF> points = getPoints();
        if (isCurve) {//曲线
            PointF pStart, pEnd;
            Path path = new Path();
            for (int i = 0; i < points.size() - 1; i++) {
                pStart = points.get(i);
                pEnd = points.get(i + 1);
                PointF point3 = new PointF();
                PointF point4 = new PointF();
                float wd = (pStart.x + pEnd.x) / 2;
                point3.x = wd;
                point3.y = pStart.y;
                point4.x = wd;
                point4.y = pEnd.y;
                path.moveTo(pStart.x, pStart.y);
                path.cubicTo(point3.x, point3.y, point4.x, point4.y, pEnd.x, pEnd.y);
                //减去文字和指示标的高度
                path.lineTo(pEnd.x, getHeight() - mXTextHeight);
                path.lineTo(pStart.x, getHeight() - mXTextHeight);
            }
            path.close();
            canvas.drawPath(path, mShadowPaint);
        } else {
            Path path = new Path();
            path.moveTo(points.get(0).x, points.get(0).y);
            for (int i = 1; i < points.size(); i++) {
                path.lineTo(points.get(i).x, points.get(i).y);
            }
            //链接最后两个点
            int index = points.size() - 1;
            path.lineTo(points.get(index).x, getHeight() - mXTextHeight);
            path.lineTo(points.get(0).x, getHeight() - mXTextHeight);
            path.close();
            canvas.drawPath(path, mShadowPaint);
        }
    }
 
    /**
     * 获取坐标点
     */
    private List<PointF> getPoints() {
        ArrayList<PointF> points = new ArrayList<>();
        for (Pair<Float, Float> pair : nodeValue) {
            points.add(new PointF((float) pair.first, (float) pair.second));
        }
        return points;
    }
 
    /**
     * 绘制底部的X轴线
     */
    private void drawBottomLine(Canvas canvas) {
        canvas.drawLine(0, mHeight - mXTextHeight, cScreenWidth, mHeight - mXTextHeight, mBottomLinePaint);
    }
 
    /**
     * 绘制X轴标签文字
     */
    private void drawBottomText(Canvas canvas) {
        for (int i = 0; i < dataValue.size(); i++) {
            String xValue = dataValue.get(i).first;
            // 获取Text内容宽度
            Rect bounds = new Rect();
            mXTextPaint.getTextBounds(xValue, 0, xValue.length(), bounds);
            int width = bounds.right - bounds.left;
            canvas.drawText(xValue, mSideLength - width / 2f + mSpaceLength * i, mHeight - mXTextHeight / 2f, mXTextPaint);
        }
    }
 
    /**
     * 绘制Y轴上的数据和背景
     */
    private void drawYtext(Canvas canvas) {
        for (int i = 0; i < dataValue.size(); i++) {
            Pair<String, Float> pair = dataValue.get(i);
            // 用Rect计算Text内容宽度
            Rect bounds = new Rect();
            mYTextPaint.getTextBounds(pair.first, 0, pair.first.length(), bounds);
            int textWidth = bounds.right - bounds.left;
            // 绘制节点上的文字
            canvas.drawText(yValue.get(i), mSideLength + mSpaceLength * i - textWidth / 2f, pair.second - 25, mYTextPaint);
        }
    }
}

2.xml里引入

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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.package.line.CurveView
        android:id="@+id/curveView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f2f2f2"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

3.activity中使用

package com.package;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.os.Bundle;
 
import com.package.line.CurveView;
 
import java.util.Arrays;
import java.util.List;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        CurveView curveView = findViewById(R.id.curveView);
          List<String> xList = Arrays.asList("1","2","3","4","5","6","7");
        List<String> yList = Arrays.asList("0","50","55","51","53","56","59");
        curveView.setData(xList, yList);
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android利用Canvas类绘制图形

    本文实例为大家分享了Android利用Canvas类绘制图形的具体代码,供大家参考,具体内容如下 首先介绍一下相关基础知识. 1.画笔(paint) 1.1.作用:画笔对象通过属性来设置笔的颜色.粗细.风格等. 1.2.设置图形绘制属性相关方法: setARGB():设置画笔的颜色:setAlpha():设置绘制图形的透明度:setStyle():设置画笔的样式风格:setStrockWidth():设置画笔的宽度: 1.3.设置文本绘制属性的相关方法: setTextSize():设置字体的大

  • Android绘制简单条形图

    本文实例为大家分享了Android绘制简单条形图的具体代码,供大家参考,具体内容如下 一种方案是:path先添加一个圆角矩形,再添加一个角的正方形 另一种直接通过api ,radii 需要传入8个数值,分四组,从左上角开始 addRoundRect(RectF rect, float[] radii, Direction dir) 中间有个小点:如果在一个循环里,同时画柱子和文字,会出现前面3个柱子上的文字被柱子覆盖,只有最后1个柱子才展示文字标记. 比如说1是柱子,2是文字,画个柱子,画个文字

  • Android绘制文本与图片及动效详解

    目录 绘制文本 绘制图片 绘制路径 逐帧动画 补间动画 绘制文本 绘制类 借助 Canvas 类进行绘制 通过重写View.onDraw 方法来进行旁白描绘 package com.mingrisoft; import android.app.Fragment; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics

  • Android自定义View实现绘制水波浪温度刻度表

    目录 前言 1.onMeasure重新测量 2.绘制刻度 3. 设置刻度动画 4. 绘制中心的圆与文字 5. 水波纹动画 后记 前言 之前的绘制圆环,我们了解了如何绘制想要的形状和进度的一些特点,那么此篇文章我们更近一步,绘制一个稍微复杂一点的刻度与波浪.来一起复习一下Android的绘制. 相对应的这种类型的自定义View网上并不少见,但是如果我们要做一些个性化的效果,最好还是自己绘制一份,也相对的比较容易控制效果,如果想实现上面的效果,我们一般来说分为以下几个步骤: 重写测量方法,确保它是一

  • Android开发自定义控件之折线图实现方法详解

    本文实例讲述了Android开发自定义控件之折线图实现方法.分享给大家供大家参考,具体如下: 前言 折线图是Android开发中经常会碰到的效果,但由于涉及自定义View的知识,对许多刚入门的小白来说会觉得很高深.其实不然,接下来我就以尽量通俗的语言来说明下图折线图效果的实现过程. 效果图 实现过程 首先,选择自定义控件的方式. 自定义控件的实现有四种方式: 1.继承View,重写onDraw.onMeasure等方法. 2.继承已有的View(比如TextView). 3.继承ViewGrou

  • python绘制散点图和折线图的方法

    本文实例为大家分享了python绘制散点图和折线图的具体代码,供大家参考,具体内容如下 #散点图,一般和相关分析.回归分析结合使用 import pandas import matplotlib import matplotlib.pyplot as plt   plot_circle=pandas.read_csv('D://Python projects//reference data//6.1//data.csv') #定义主题颜色 maincolor=(47/256,82/256,141

  • C#绘制柱状图和折线图的方法

    本文实例为大家分享了C#绘制柱状图和折线图的具体代码,供大家参考,具体内容如下 运行效果如下图: 设计上面的柱状图和折线图其实并没有什么难度,主要是各个坐标的计算,完全是精细活.首先在窗体在添加了一个tabControl控件来切换柱状图和折线图的显示,在tabPage1中显示柱状图,在tabPage2中显示折线图.然后在各自的Page页属性中定义Paint事件,具体实现过程可以从下面的代码中看到. 代码如下: 添加头文件: using System.Drawing.Drawing2D; tabP

  • Python基于Matplotlib库简单绘制折线图的方法示例

    本文实例讲述了Python基于Matplotlib库简单绘制折线图的方法.分享给大家供大家参考,具体如下: Matplotlib画折线图,有一些离散点,想看看这些点的变动趋势: import matplotlib.pyplot as plt x1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] y1=[30,31,31,32,33,35,35,40,47,62,99,186,480] x2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1

  • extjs4图表绘制之折线图实现方法分析

    本文实例讲述了extjs4图表绘制之折线图实现方法.分享给大家供大家参考,具体如下: 本篇文章将介绍extjs中自带的图表 在本次案例中,提供一下功能: 1.从后端请求数据并运用到图表中,形成动态数据. 2.查询出每年各个月中人数. 请看下面代码: Ext.define('ChartLineTest', { extend: 'Ext.panel.Panel', autoScroll : true, selectYear:null,//定义年份 initComponent: function ()

  • Android画图实现MPAndroidchart折线图示例详解

    目录 效果图 依赖 activity.xml MainActivity MyMarkerView 自定义class maekertextview .xml 常用属性 效果图 用的是3.1.0的依赖 依赖 allprojects { repositories { jcenter() maven { url "https://jitpack.io" } } } //依赖 dependencies{ implementation 'com.github.PhilJay:MPAndroidCh

  • Android自定义View实现折线图效果

    下面就是结果图(每种状态用一个表情图片表示): 一.主页面的布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&quo

  • jQuery实现折线图的方法

    本文实例讲述了jQuery实现折线图的方法.分享给大家供大家参考.具体如下: 效果图如下所示: js引用: 复制代码 代码如下: <script src="Js/Index/jquery-1.5.2.min.js" type="text/javascript"></script>  <script src="js/Index/raphael.2.1.0.min.js" type="text/javascri

  • 使用python matploblib库绘制准确率,损失率折线图

    我就废话不多说了,大家还是直接看代码吧~ import matplotlib.pyplot as plt epochs = [0,1,2,3] acc = [4,8,6,5] loss = [3,2,1,4] plt.plot(epochs,acc,color='r',label='acc') # r表示红色 plt.plot(epochs,loss,color=(0,0,0),label='loss') #也可以用RGB值表示颜色 #####非必须内容######### plt.xlabel(

  • vue+echarts实现动态折线图的方法与注意

    之前公司有个绘制实时盈利率折线图的需求,实现的还不错,今天来分享下vue+echarts实现动态折线图的方法. 实现代码 <template> <div id="myChart"></div> </template> <script> import echarts from 'echarts' export default { name: 'DynamicLineChart', data () { return { // 实时

随机推荐