转载请注明出处:http://write.blog.csdn.net/postedit/50434634

接上篇 Android 圆形百分比(进度条) 自定义view

昨天分手了,不开心,来练练自定义view麻痹自己,毕竟菜鸟只能靠不断练习提高。#程序员不应该有女朋友#

我们要实现的是一种只有来看趋势,不需要看具体数值,比较简约的折线图。比如下图这样的:

这个时候,一些比较优秀的第三方图表库如:MPChart 就显得比较臃肿了。所以我们需要自定义一个折线图。

老规矩,先来看最终的实现效果:

其实这种做的很简约,大概分三个步骤:

一、画坐标轴

二、画点

三、画线

那么我们开始吧Let's go (Let it go)。

设计一下大概需要的东西。首先把X轴和Y轴的数据存放在两个String[]里。

具体的点的位置用一个Map<Integer,Integer>来存放.

步骤:

一、新建一个类,取名为SimpleLineChart继承View 重写他的构造方法。这里为了简便,就不添加自定义属性了attr.xml。

<span style="font-size:18px;">   </span><span style="font-size:12px;"> public SimpleLineChart(Context context) {this(context, null);}public SimpleLineChart(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SimpleLineChart(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}</span>

二、测量大小。(继续偷懒,只支持EXACTLY,AT_MOST直接丢异常)

@Overrideprotected 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 (widthMode == MeasureSpec.EXACTLY) {mWidth = widthSize;}else if(widthMode == MeasureSpec.AT_MOST){throw new IllegalArgumentException("width must be EXACTLY,you should set like android:width=\"200dp\"");}if (heightMode == MeasureSpec.EXACTLY) {mHeight = heightSize;}else if(widthMeasureSpec == MeasureSpec.AT_MOST){throw new IllegalArgumentException("height must be EXACTLY,you should set like android:height=\"200dp\"");}setMeasuredDimension(mWidth, mHeight);}

三、重点来了,开始draw。首先处理几种异常情况。当X轴或者Y轴为没有文字(也就是没有刻度的时候),抛出异常。

if(mXAxis.length==0||mYAxis.length==0){throw new IllegalArgumentException("X or Y items is null");}

当没有任何点的数据的时候,显示字符串提醒用户没有数据(实际上是往中心drawText)。

 //画坐标线的轴Paint axisPaint = new Paint();axisPaint.setTextSize(mYAxisFontSize);axisPaint.setColor(Color.parseColor("#3F51B5"));
if (mPointMap == null || mPointMap.size() == 0) {int textLength = (int) axisPaint.measureText(mNoDataMsg);canvas.drawText(mNoDataMsg, mWidth/2 - textLength/2, mHeight/2, axisPaint);} 

异常情况处理完了,开始上面三个步骤挨个画,首先来画个Y轴,计算每个刻度的间隔。他的值应该是mWidth / Y轴文字个数,然后用循环把每个刻度都画出来。再申请一个数组yPoints,存放每个Y刻度的具体坐标。

  //画 Y 轴//存放每个Y轴的坐标int[] yPoints = new int[mYAxis.length];//计算Y轴 每个刻度的间距int yInterval = (int) ((mHeight - mYAxisFontSize - 2) / (mYAxis.length));//测量Y轴文字的高度 用来画第一个数Paint.FontMetrics fm = axisPaint.getFontMetrics();int yItemHeight = (int) Math.ceil(fm.descent - fm.ascent);Log.e("wing", mHeight + "");for (int i = 0; i < mYAxis.length; i++) {canvas.drawText(mYAxis[i], 0, mYAxisFontSize + i * yInterval, axisPaint);yPoints[i] = (int) (mYAxisFontSize + i * yInterval);}

我们运行一下,看到了如下效果:

需要注意的是,这里的坐标需要微调,大家多试一下。同理开始画X轴:

      //画 X 轴//x轴的刻度集合int[] xPoints = new int[mXAxis.length];Log.e("wing", xPoints.length + "");//计算Y轴开始的原点坐标int xItemX = (int) axisPaint.measureText(mYAxis[1]);//X轴偏移量int xOffset = 50;//计算x轴 刻度间距int xInterval = (int) ((mWidth - xOffset) / (mXAxis.length));//获取X轴刻度Y坐标int xItemY = (int) (mYAxisFontSize + mYAxis.length * yInterval);for (int i = 0; i < mXAxis.length; i++) {canvas.drawText(mXAxis[i], i * xInterval + xItemX + xOffset, xItemY, axisPaint);xPoints[i] = (int) (i * xInterval + xItemX + axisPaint.measureText(mXAxis[i]) / 2 + xOffset + 10);
//            Log.e("wing", xPoints[i] + "");}

注意这里X轴的y坐标就是画Y轴时候的最下面的文字(最后一个)的坐标,存成了xItemY。

之后我们来画点,这里我采用的方法是画圆。直接drawCircle。从map中取出所有点的对应i,j然后再从两个数组 xPoints[] yPoints[]取出真实的X,Y坐标,最后画出来

        //画点Paint pointPaint = new Paint();pointPaint.setColor(mLineColor);Paint linePaint = new Paint();linePaint.setColor(mLineColor);linePaint.setAntiAlias(true);//设置线条宽度linePaint.setStrokeWidth(mStrokeWidth);pointPaint.setStyle(Paint.Style.FILL);for (int i = 0; i < mXAxis.length; i++) {if (mPointMap.get(i) == null) {throw new IllegalArgumentException("PointMap has incomplete data!");}//画点canvas.drawCircle(xPoints[i], yPoints[mPointMap.get(i)], mPointRadius, pointPaint);if (i > 0) {//画线canvas.drawLine(xPoints[i - 1], yPoints[mPointMap.get(i - 1)], xPoints[i], yPoints[mPointMap.get(i)], linePaint);}}

上面画完点之后开始画线drawLine,参数是前一个点的坐标,和后一个点的坐标。挨个画出来。

这时候我们的最复杂的绘制就完成了。接下来来加入一点功能:参数的设置。

 /*** 设置map数据* @param data*/public void setData(HashMap<Integer,Integer> data){mPointMap = data;invalidate();}/*** 设置Y轴文字* @param yItem*/public void setYItem(String[] yItem){mYAxis = yItem;}/*** 设置X轴文字* @param xItem*/public void setXItem(String[] xItem){mXAxis = xItem;}public void setLineColor(int color){mLineColor = color;invalidate();}

以上代码很简单 我就不多说了。整个View完工,接下来介绍如何使用。

使用:

和普通的View一样,我们直接在XML布局文件中加入SimpleLineChart,注意不要忘记包名。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingBottom="@dimen/activity_vertical_margin"tools:context="com.wingsofts.simplelinechart.MainActivity"><com.wingsofts.simplelinechart.SimpleLineChartandroid:id="@+id/simpleLineChart"android:layout_width="400dp"android:layout_height="200dp" />
</RelativeLayout>

然后在Activity中findviewbyid,给他设置X轴的文字 Y轴的文字 还有数据源

public class MainActivity extends AppCompatActivity {private SimpleLineChart mSimpleLineChart;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mSimpleLineChart = (SimpleLineChart) findViewById(R.id.simpleLineChart);String[] xItem = {"1","2","3","4","5","6","7"};String[] yItem = {"10k","20k","30k","40k","50k"};if(mSimpleLineChart == null)Log.e("wing","null!!!!");mSimpleLineChart.setXItem(xItem);mSimpleLineChart.setYItem(yItem);HashMap<Integer,Integer> pointMap = new HashMap();for(int i = 0;i<xItem.length;i++){pointMap.put(i, (int) (Math.random()*5));}mSimpleLineChart.setData(pointMap);}
}

简单的几步,就可以得到预览图的效果了!是不是很好玩!觉得好的话评论一下,star一下。祭奠我死去的爱情。

项目下载地址(求关注 求星星 ):点击打开链接

下一篇来一个比较炫 比较复杂的view 自定义仪表盘 :时尚自定义仪表盘

转载于:https://www.cnblogs.com/muyuge/p/6333560.html

Android 自定义View -- 简约的折线图相关推荐

  1. Android自定义View——实现理财类APP七日年化收益折线图效果

    这段时间的自定义View学习,学会了绘制柱状图.绘制折线图.绘制进度控件,那我们今天就来聊聊另外一种自定义的View,这就是我们常见的七日年化收益折线图效果.先看看长什么样. 这就是效果图了,元素相对 ...

  2. android 轨迹生成图,Android自定义View实现公交成轨迹图

    本文实例为大家分享了Android自定义View实现公交成轨迹图的具体代码,供大家参考,具体内容如下 总体分析下:水平方向recyclewview,item包含定位点,站台位置和站台名称. 下面看实现 ...

  3. Android自定义View实现三角到八角的属性分布图-雷达图(蜘蛛网图)

    Android自定义View实现三角到八角的属性分布图-雷达图(蜘蛛网图) 前言 自定义View的关键点 绘制多边形 结尾 前言 刚开始学习自定义view,简单完成了一个属性分布器,可以实现三条到八条 ...

  4. android自定义View: 饼状图绘制(四)

    本系列自定义View全部采用kt 系统mac android studio: 4.1.3 kotlin version1.5.0 gradle: gradle-6.5-bin.zip 本篇效果: 画矩 ...

  5. android 自定义view: 蛛网/雷达图(三)

    本系列自定义View全部采用kt 系统mac android studio: 4.1.3 kotlin version1.5.0 gradle: gradle-6.5-bin.zip 本篇效果: 蛛网 ...

  6. 一篇文章带你走近Android自定义view

    系列文章目录 一篇文章带你走近Android自定义view 文章目录 系列文章目录 前言 一.为什么要自定义view 二.先看看一个超级简单的自定义view(三个构造函数) 三.了解手机的坐标系 四. ...

  7. Android自定义View之Paint绘制文字和线

    Android自定义View系列 Android自定义View注意事项 Android自定义View之图像的色彩处理 Android自定义View之Canvas Android自定义View之轻松实现 ...

  8. Android 自定义View —— Canvas

    上一篇在android 自定义view Paint 里面 说了几种常见的Point 属性 绘制图形的时候下面总有一个canvas ,Canvas 是是画布 上面可以绘制点,线,正方形,圆,等等,需要和 ...

  9. Android自定义View:ViewGroup(三)

    自定义ViewGroup本质是什么? 自定义ViewGroup本质上就干一件事--layout. layout 我们知道ViewGroup是一个组合View,它与普通的基本View(只要不是ViewG ...

最新文章

  1. Windows Forms高级界面组件-快捷菜单
  2. crontab 时间参数解释
  3. CentOS下创建配置RAID1
  4. 基于用户击键特征的身份鉴别系统
  5. n皇后问题(在棋盘上找方案)
  6. Flask部署工具的安装与使用
  7. 施耐德 m340 编程手册_施耐德PLC漏洞历险记
  8. C中使用errno查看函数调用的错误
  9. Chrome浏览器离线安装包下载方法
  10. 企业如何做好服务器防护45.113.201.1
  11. 手把手教你在 Vue 中使用 JSX,不怕学不会!【建议收藏】
  12. UltraCompare Crack,重复文件查找器
  13. laravel 路由_简单的Laravel路由
  14. 经典语录用心记忆,总有一句让你受益匪浅!
  15. 多点相册--将手机的照片和视频备份到电脑的工具
  16. android播放器概述,【Android】 从头搭建视频播放器(1)——概述
  17. [RL robotic 环境] - [Robosuite](1)
  18. 计算机视觉学习路线—计算机视觉入门必读的20本书
  19. tensorflow 常遇函数
  20. 3D数学系列之——从“蒙的挺准”到“蒙的真准”解密蒙特卡洛积分!

热门文章

  1. 为什么前端工程师薪资越来越高?
  2. 7-4 sdut-运输计费问题 (10 分)python
  3. JAVA中toString方法的作用
  4. python 高级_Python高级特性(一)
  5. 使用pm2后台运行nodejs程序
  6. Java功能模块代码源码_Windows计算机功能Java源码
  7. IDEA连接Git后类的颜色含义
  8. 一步一步带你安装Node.js并创建第一个Vue项目
  9. 西瓜书《贝叶斯》朴素贝叶斯公式推导
  10. VS2008编辑器代码适合的配色方案下载