我的编程空间,编程开发者的网络收藏夹
学习永远不晚

MPAndroidChart绘制自定义运动数据图表示例详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

MPAndroidChart绘制自定义运动数据图表示例详解

引言

声明:文中的MPChart代指MPAndroidChart.

本系列之前的文章介绍的MPChart中BarChart相关的一些绘制,接下来我们看看LineChart相关的绘制。

这里以实际的运动相关的图表数据做业务支撑来讲解。MPChart图表支持多指触控方法,这里所有的图表自定义都关掉了这个属性,这样就减少Transformer,以及绘制过程中的更多的变动,相当于一个静态的图。

通常图表在放大的过程中,坐标轴也会随之展现更小的刻度,复杂度就变高了,具体的显示的刻度就可能出现小数之类的等情况。

这里我们关掉触摸放大后,相当于一个静态的图。这时候,产品以及设计可能需要我们的X轴坐标、Y轴坐标等刻度尽可能地为整数,这样看起来比较美观。

静态的情况下,因为没法移动,即便可以移动,首次展现也希望图表的数据能够比较居中,这就涉及到YAxis的自定义如何影响控制 Chart的相关展示逻辑的内容,本章节首先从这入手,讲解运动数据图表的绘制。

TimeAxis

这里自定义X轴TimeAxis,实际意义是一次运动耗费的时间,继承自XAxis。假如一次运动1个小时06分钟,设计希望展示4个刻度(0, 20 , 40, 60 分钟), 这时需要我们自己去控制,假如不加控制的话,Default情况下没法准确的实现设计的需求。

XAxis、YAxis有两个属性,Maximum, Minmum. 这样设定每个interval 就可以计算出要显示的刻度列表, labelList, 加入到XAxis中的 mEntries, 最后在XAxisRender会拿到mEntries 最终绘制 X坐标。

这里不在设计一个算法类计算每个时间段的刻度显示了,运动的时间范围有限,直接枚举, 在 TimeXAxis里的getlabelCount() 实现。

  if (max > 6000 * TimeDateUtil.TIME_MIN_INT){
    interval = 2000 * TimeDateUtil.TIME_MIN_INT;
  } else if (max > 4800 * TimeDateUtil.TIME_MIN_INT) {// 80个小时
    interval = 1920 * TimeDateUtil.TIME_MIN_INT;
  } else if (max > 2400 * TimeDateUtil.TIME_MIN_INT) {// 40个小时
    interval = 960 * TimeDateUtil.TIME_MIN_INT;
  } else if (max > 1200 * TimeDateUtil.TIME_MIN_INT) {
    interval = 480 * TimeDateUtil.TIME_MIN_INT;
  }
  。。。。。
  else if (max > 20 * TimeDateUtil.TIME_MIN_INT) {
    interval = 5 * TimeDateUtil.TIME_MIN_INT;
  } else if (max > 15 * TimeDateUtil.TIME_MIN_INT) {
    interval = 4 * TimeDateUtil.TIME_MIN_INT;//4分钟刻度
  } else if (max > 5 * TimeDateUtil.TIME_MIN_INT) {//
    interval = 2 * TimeDateUtil.TIME_MIN_INT;//2分钟刻度。
  } else {
    interval = TimeDateUtil.TIME_MIN_INT;
  }
  float currentEntry = min;
  List<Float> entryList = new ArrayList<>();
  do {
    entryList.add(currentEntry);
    currentEntry += interval;
  } while (currentEntry <= max);
  labelCount = entryList.size();
  mEntryCount = labelCount;
  if (mEntries.length < labelCount) {
    mEntries = new float[labelCount];
  }
  for (int i = 0; i < labelCount; i++) {
    mEntries[i] = entryList.get(i);
  }

准备好XAxis 中的Entry数据后,依旧是交给Buffer,经过Transformer转化,最终绘制出来, 自定义TimeAxisRender, 然后 renderAxisLabels() 方法里drawLabel(), 绘制XAxis的坐标轴线:

图1.0 XAxis 坐标线的绘制

SportYAxis

Y轴的绘制相比XAxis要复杂一些,自定义的SportYAxis继承自YAxis, TimeXAxis 只有时间数据对应。SportYAxis根据具体的数据业务可以表示 心率, 高度海拔, 速度, 配速,频率等数据。

这些数据中, 心率、步频等取值范围可以比如(0, 250)类似这样的可以直接定下来Y轴的Max, Min 值以及对应的刻度,高度海拔有负数的,速度的Max根据 所给数据来定, 配速比较特殊,需要将Y轴 revert。

为了将图表能够居中,通常YAxis 上的Maximum 会比 数据中的极大值要偏大,保证图表不会呈现的太慢,影响美观。根据不同的Sport数据,将Y轴分为以下几种:

// TYPE_FIX_MIN_ZERO = 0; Y轴从固定的0开始 到 max;步频、起跳高度
// TYPE_FIX_MIN_POSITIVE = 1; 从 entryList的 真实的 min(min不能小于0)开始,到max; 心率、速度、划频、Swolf
// TYPE_FIX_COMMON = 2; 从entryList的最小值min开始到max的最大值,无论最大、最小是否为Positive, 例如海拔;
//TYPE_FIX_RESTRICT_MAX = 3; 限制最大值,比如配速。Y轴 Invert,所以最小值min为大于等于 0 的Positive value; 配速
public static final int TYPE_FIX_MIN_ZERO = 0;
public static final int TYPE_FIX_MIN_POSITIVE = 1;
public static final int TYPE_FIX_COMMON = 2;
public static final int TYPE_FIX_RESTRICT_MAX = 3;

每种类型下计算Y轴的Maximum、Minmum; 然后计算刻度的间距 itemValue, 得到 坐标Label 的List。

以上的几种坐标的实现具体在 SportYAxis 中实现。

将Y轴数据限定下来之后,图表的展现因为Y轴的Maximum、Minmum 限定在比较居中的位置。

对于配速,当运动停下来时,单位距离的耗时可能无限大,假如我们考虑把这个极值画下来的话,Y轴可能跨度很大导致图表没法看,所以需要限定极大值,截断图形:

//限制最大值
private float getYAxisMax2(List<SportRecordEntry> values, float yAxisMin) {
    int size = values.size();
    float yAxisMax = Integer.MIN_VALUE;
    float yAxisMinTemp = Integer.MAX_VALUE;
    float sum = 0;
    for (int i = 0; i < size; i++) {
      SportRecordEntry entry = values.get(i);
      yAxisMax = Math.max(entry.getY(), yAxisMax);
      yAxisMinTemp = Math.min(entry.getY(), yAxisMinTemp);
      sum += entry.getY();
    }
    float averageY = sum / (size * 1.0f);
    float distanceMin = averageY - yAxisMinTemp;
    float distanceMax = yAxisMax - averageY;
    int num = (int) (distanceMax / distanceMin);
    if (num > 5) {// 配速中 有 配速值很慢的点,坐标时不考虑它们了。
      yAxisMax = averageY + 2 * distanceMin; // 限制Y 轴坐标。
    }
    float distance = yAxisMax - yAxisMin;
    if (yAxisMax > 0 && distance <= 2) {
      return yAxisMax + 2;
    }
    return yAxisMax + distance * mLineChartAttr.maxYAxisRatio;
}

CustomLineChart

处理完XAxis、YAxis的数据及绘制后,处理LineChart的主体,这里包含了折线图、曲线图等体现数据展现的,还有drawFill, 底部的填充;drawMaxMinPop() 极值点的绘制等。

着重讲解折线图的绘制,对于LineChart,Entry比较简单,存有对应的X, Y值,

图1.1CustomLineChart 绘制逻辑

考虑先后两个点,PreEntry, CurrentEntry 然后 绘制每段折线,最终连成图表。

针对 配速图表Y轴需要倒过来的,

private float getYAsInverted(Entry entry) {
    final float phaseY = mAnimator.getPhaseY();
    float yValueRange = mYAxis.getAxisMaximum() - mYAxis.getAxisMinimum();
    if (mYAxis.isInverted()) {
      if (entry.getY() <= mYAxis.getAxisMinimum()) {
        return entry.getY() * phas
        eY;
      } else {
        return (yValueRange - entry.getY()) * phaseY;
      }
    } else {
      return entry.getY() * phaseY;
    }
}

以下就是配速图表,极大值的限定线取的太大,导致整个图形太偏上了,可以做响应的修改。

图1.2配速图表线形图

绘制底部的Fill, 将所有的点连线,再连接到底部的X点坐标,最后形成闭环的Path,

图1.3 drawFill

以上大致就是线性图表的绘制逻辑,考虑X轴、Y轴的Label的设定,绘制,Y轴的极值设定来控制图表图形呈现的位置;配速表的这种Y轴图形的invert, 底部的drawFill().

自此大体的自定义绘制讲解完了。后续会做些补充,步频散点图,极值的绘制,RTL相关等。

以上就是MPAndroidChart 自定义运动数据图表示例详解的详细内容,更多关于MPAndroidChart 运动数据图表的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

MPAndroidChart绘制自定义运动数据图表示例详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

vue的表单数据收集案例之基本指令和自定义指令详解

收集表单数据可以使用这个v-model实现这个数据的绑定,但是在有些输入框中,还需要一些其他的指令搭配这个v-model指令结合使用,这篇文章主要介绍了vue的表单数据收集,基本指令和自定义指令,需要的朋友可以参考下
2023-01-05

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录