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

 更新时间:2020年5月21日 16:23  点击:2085

本文实例讲述了Android开发自定义控件之折线图实现方法。分享给大家供大家参考,具体如下:

前言

折线图是Android开发中经常会碰到的效果,但由于涉及自定义View的知识,对许多刚入门的小白来说会觉得很高深。其实不然,接下来我就以尽量通俗的语言来说明下图折线图效果的实现过程。

效果图

实现过程

首先,选择自定义控件的方式。

自定义控件的实现有四种方式:

1.继承View,重写onDraw、onMeasure等方法。
2.继承已有的View(比如TextView)。
3.继承ViewGroup实现自定义布局。
4.继承已有的ViewGroup(比如LinearLayout)。

由于我们不需要多个控件进行组合,也不需要在原有控件基础上改造,故我们采用第1种方式即继承View来实现。代码如下,新建一个ChartView类继承自View,并实现他的几个构造方法,并重写onDraw和onMeasure方法,因为我们要在onDraw方法里面进行绘制工作,并且我希望这个控件的长宽是相等的,所以在onMeasure方法设置宽高相等。设置长宽相等的方式很简单,我们不需要自己去测量实现,只需要调用父类的onMeasure方法,传参数(宽高值)时将都传入宽度(或者高度)即可。

public class ChartView extends View {

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

  public ChartView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
  }

  public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
  }

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

其次,绘制简单图形并显示出来。

在进行绘制之前,我们要进行若干初始化工作,其中就包括画笔的初始化。然后就可以进行绘制了,我们先绘制一个简单的圆圈,然后将控件放到布局文件中,运行看看效果。

ChartView代码

public class ChartView extends View {

  // 画笔
  private Paint paint;

  /**
  * 构造函数
  */
  public ChartView(Context context) {
    super(context);
    initWork();
  }

  /**
  * 构造函数
  */
  public ChartView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    initWork();
  }

  /**
  * 构造函数
  */
  public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initWork();
  }

  /**
  * 初始化工作
  */
  private void initWork() {
    initPaint();
  }

  /**
  * 画笔设置
  */
  private void initPaint() {
    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    // 画笔样式为填充
    paint.setStyle(Paint.Style.FILL);
    // 颜色设为红色
    paint.setColor(Color.RED);
    // 宽度为3像素
    paint.setStrokeWidth(3);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 画圆
    canvas.drawCircle(300,300,100,paint);
  }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"

  <com.toprs.linechart.ChartView
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

</android.support.constraint.ConstraintLayout>

效果:

然后,绘制图表。

到目前为止,已经实现了最简单的一个自定义控件,虽然它什么功能都没有,只是简单显示一个红色圆圈,但本质都是一样的。接下来就开始图表的绘制。

1.初始化一些需要使用的值。

  // 刻度之间的距离
  private int degreeSpace;

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 控件上下左右边界四至及控件的宽度(同时也是高度!)
    int left = getLeft();
    int right = getRight();
    int top = getTop();
    int bottom = getBottom();
    int w = getWidth();

    // 图表距离控件边缘的距离
    int graphPadding = w / 10;
    // 图表上下左右四至
    int graphLeft = left + graphPadding;
    int graphBottom = bottom - graphPadding;
    int graphRight = right - graphPadding;
    int graphTop = top + graphPadding;
    // 图表宽度(也等同高度奥~)
    int graphW = graphRight - graphLeft;
    // 刻度之间的距离
    degreeSpace = graphW / 8;
  }

2.灰色背景

  // 背景
  canvas.drawColor(Color.LTGRAY);

3.坐标系

  // 画笔设置样式为STROKE样式,即只划线不填充
  paint.setStyle(Paint.Style.STROKE);

  // 坐标系绘制
  Path pivotPath = new Path();
  //Y轴
  pivotPath.moveTo(graphLeft, graphBottom);
  pivotPath.lineTo(graphLeft, graphTop);
  //Y轴箭头
  pivotPath.lineTo(graphLeft - 12, graphTop + 20);
  pivotPath.moveTo(graphLeft, graphTop);
  pivotPath.lineTo(graphLeft + 12, graphTop + 20);
  //X轴
  pivotPath.moveTo(graphLeft, graphBottom);
  pivotPath.lineTo(graphRight, graphBottom);
  //X轴箭头
  pivotPath.lineTo(graphRight - 20, graphBottom + 12);
  pivotPath.moveTo(graphRight, graphBottom);
  pivotPath.lineTo(graphRight - 20, graphBottom - 12);
  canvas.drawPath(pivotPath, paint);

4.刻度虚线及数字

  // Y轴刻度虚线
  for (int i = 1; i < 8; i++) {
    Path yKeduPath = new Path();
    // 线
    paint.setColor(Color.WHITE);
    paint.setStrokeWidth(1);
    paint.setStyle(Paint.Style.STROKE);
    paint.setPathEffect(new DashPathEffect(new float[]{5,5},0));
    yKeduPath.moveTo(graphLeft, graphBottom - i * degreeSpace);
    yKeduPath.lineTo(graphRight, graphBottom - i * degreeSpace);
    canvas.drawPath(yKeduPath, paint);
    // 数字
    paint.setColor(Color.BLACK);
    paint.setStyle(Paint.Style.FILL);
    paint.setTextSize(25);
    paint.setPathEffect(null);
    canvas.drawText(i + "", graphPadding / 2, graphBottom - i * degreeSpace, paint);
  }
  // X轴刻度虚线
  for (int i = 1; i < 8; i++) {
    Path xKeduPath = new Path();
    // 线
    paint.setColor(Color.WHITE);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(1);
    paint.setPathEffect(new DashPathEffect(new float[]{5,5},0));
    xKeduPath.moveTo(graphLeft + i * degreeSpace, graphBottom);
    xKeduPath.lineTo(graphLeft + i * degreeSpace, graphTop);
    canvas.drawPath(xKeduPath, paint);
    // 数字
    paint.setColor(Color.BLACK);
    paint.setStyle(Paint.Style.FILL);
    paint.setTextSize(25);
    paint.setPathEffect(null);
    canvas.drawText(i + "", graphLeft + i * degreeSpace, graphBottom + graphPadding / 2, paint);
  }

5.折线

在绘制折线之前,我们先要初始化几个参数。

  // 模拟数据
  private float[] data = {3.2f, 4.3f, 2.5f, 3.2f, 3.8f, 7.1f, 1.3f, 5.6f};
  // 当前显示的数据数量
  private int showNum=1;

  // 折线
  Path linePath = new Path();
  for (int i = 0; i < showNum; i++) {
    int toPointX = graphLeft + i * degreeSpace;
    int toPointY = graphBottom - ((int) (data[i] * degreeSpace));
    paint.setColor(Color.YELLOW);
    paint.setStyle(Paint.Style.STROKE);
    if (i==0){
      linePath.moveTo(toPointX,toPointY);
    }else {
      linePath.lineTo(toPointX, toPointY);
    }
    // 节点圆圈
    canvas.drawCircle(toPointX, toPointY,10,paint);
    paint.setColor(Color.WHITE);
    paint.setStyle(Paint.Style.FILL);
    canvas.drawCircle(toPointX,toPointY,7,paint);
  }
  paint.setColor(Color.YELLOW);
  paint.setStyle(Paint.Style.STROKE);
  paint.setStrokeWidth(3);
  canvas.drawPath(linePath, paint);

6.让图表动起来

为了实现数据依次显现的动画,我们开启一个线程是当前显示的数据数量即showNum变量不断加一,并间隔时间0.5秒。然后postInvalidate()重绘即可。

  private void initWork() {
    initPaint(); 
    // 开启线程,没隔0.5秒showNum加一
    new Thread(new Runnable() {
      @Override
      public void run() {
        while (true){
          if (showNum<data.length){
            showNum++;
          }else {
            showNum=1;
          }
          // 重绘
          postInvalidate();
          // 休眠0.5秒
          try {
            Thread.sleep(500);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }).start();
  }

好了,运行一下,便会实现上面的效果了。如果你觉得效果不够炫酷或者功能太少,那就自己完善吧~~

结语

由于自定义控件是Android进阶路上必然要碰到的知识,所以希望大家重视。其实自定义控件说难也难说简单也简单。实现一些普通的效果还是很方便的,像这次举的例子,但如果要实现各种炫酷效果并且要完善各种功能的话,就需要各种知识的配合了,包括数学、物理、绘图等知识。所以还是需要平时不断积累的,看到别人的控件很棒的时候自己可以试着去实现一下,对自己的知识库不断进行补充,自然会娴熟的运用。本人也是菜鸟一枚,望共勉!!

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android控件用法总结》、《Android开发入门与进阶教程》、《Android视图View技巧总结》、《Android编程之activity操作技巧总结》、《Android数据库操作技巧总结》及《Android资源操作技巧汇总》

希望本文所述对大家Android程序设计有所帮助。

[!--infotagslink--]

相关文章

  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20
  • Android 实现钉钉自动打卡功能

    这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
  • Android 开发之布局细节对比:RTL模式

    下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
  • Android中使用SDcard进行文件的读取方法

    首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
  • Android开发之PhoneGap打包及错误解决办法

    下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
  • 用Intel HAXM给Android模拟器Emulator加速

    Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20
  • Android判断当前屏幕是全屏还是非全屏

    在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20
  • Android开发中布局中的onClick简单完成多控件时的监听的利与弊

    本文章来为各位介绍一篇关于Android开发中布局中的onClick简单完成多控件时的监听的利与弊的例子,希望这个例子能够帮助到各位朋友. 首先在一个控件加上这么一句:and...2016-09-20
  • 解析C#自定义控件的制作与使用实例的详解

    本篇文章是对C#中自定义控件的制作与使用实例进行了详细的分析介绍,需要的朋友参考下...2020-06-25
  • Ubuntu 系统下安装Android开发环境 Android Studio 1.0 步骤

    Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试,可以在Linux,Mac OS X,Window...2016-09-20