Android 图表开发开源库 MPAndroidChart 使用总结

1. 引言

电视项目中需要一个折线图表示节电数据变化情况,类比 H5 来说,Android 中也应该有比较成熟的控件,经过调研后,发现 MPAndroidChart 功能比较强大,网上也有人说可能是目前 Android 开发最好用的一个三方库了,功能非常强大,集成简单。

这里把我的集成使用过程及使用中发现的强大惊喜记录下来,留作团队财富,可供后续参考。

首先,简单的介绍下强大的 MPAndroidChart,它支持常用的各种图:柱状图(横向,竖向)、线状图(多种效果)、饼状图、点状图,属性也很简单,我们使用的时候只需要熟悉控件的 11 各种属性即可。核心功能如下:

  • 支持 x,y 轴缩放

  • 支持拖拽

  • 支持手指滑动

  • 支持高亮显示

  • 支持保存图表到文件中

  • 支持从文件(txt)中读取数据

  • 预先定义颜色模板

  • 自动生成标注

  • 支持自定义 x,y 轴的显示标签

  • 支持 x,y 轴动画

  • 支持 x,y 轴设置最大值和附加信息

  • 支持自定义字体,颜色,背景,手势,虚线等

2. 集成

集成很简单,直接导入作为依赖就可以,以下写了一个最小集成的例子,主要为了说明步骤:

2.1 引入依赖到工程中

// 项目工程的 build.gradle
repositories {maven { url "https://jitpack.io" }
}// Module的 build.gradle
dependencies {implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}

2.2 Layout 中添加控件

<!--节电折线图-->
<com.github.mikephil.charting.charts.LineChartandroid:id="@+id/chart1"android:layout_width="0dp"android:layout_height="0dp"android:layout_alignParentTop="true"android:layout_alignParentBottom="true"android:layout_alignParentStart="true"android:layout_alignParentEnd="true"android:layout_marginTop="@dimen/tvcommon_px131"android:layout_marginBottom="@dimen/tvcommon_px60"android:layout_marginStart="@dimen/tvcommon_px44"android:layout_marginEnd="@dimen/tvcommon_px30" />

2.3 Activity 中使用

// 3.4 节电详情页
mChart = findViewById(R.id.chart1)
initChat()
setChatData()

2.3.1 初始化

private fun initChat() {mChart.setBackgroundColor(resources.getColor(R.color.color_00000000))mChart.description.isEnabled = false// 2. X 轴样式val xAxis: XAxis = mChart.getXAxis()xAxis.setDrawGridLines(false)// xAxis.enableGridDashedLine(10f, 10f, 0f);xAxis.position = XAxis.XAxisPosition.BOTTOM// 3. Y轴样式mChart.axisRight.isEnabled = false  // disable dual axis (only use LEFT axis)var yAxis: YAxis = mChart.axisLeftyAxis.axisMaximum = 200fyAxis.axisMinimum = 0f
}

2.3.2 Activity 中设置数据

public void setChatData(){List<Entry> entries=new ArrayList<>();List<Entry> entries1=new ArrayList<>();entries.add(new Entry(3f,20));entries1.add(new Entry(5f,30));LineDataSet dataSet=new LineDataSet(entries,"数据一");LineDataSet dataSet1=new LineDataSet(entries1,"数据二");List<ILineDataSet> list=new ArrayList<>();list.add(dataSet);list.add(dataSet1);LineData lineData=new LineData(list);mChat.setData(lineData); //将模拟数据用于线形图,在线形图显示}

2.3.3 大功告成

3. 使用总结

MPAndroidChart 的强大之处在于它的很多功能都可定制,只要你有想法,大部分都有解决方法,哪怕一时没有,只要肯找,说不准就能发现。

电视项目中要求的是一个折线图,所以这里的使用总结大多集中在折线及我们要实现的效果上,其它未涉及的图和属性暂时不写,后续使用的时候再作探索及总结。

3.1 整体功能及专业术语一览(网上找的一张图,镇楼,哈哈)

3.2 基础设置 (非数据类型,在初始化时设置)

首先,在 initChat()函数中,进行了一些基础设置,把一些用不到的功能关闭:

private fun initChat() {mChart.setBackgroundColor(resources.getColor(R.color.color_00000000))mChart.description.isEnabled = falsemChart.setTouchEnabled(false)mChart.setDrawGridBackground(false)mChart.isDragEnabled = falsemChart.setScaleEnabled(false)mChart.setPinchZoom(false)mChart.legend.isEnabled = false
}

3.3 x、y 轴设置 (非数据类型,在初始化时设置)

这个也不属于数据设置,所以在初始化时进行,如下,分别进行了线宽,线颜色,Label 的字体大小、颜色、还有网格线:

private fun initChat() {...// 2. X 轴样式val xAxis: XAxis = mChart.getXAxis()xAxis.setDrawGridLines(false)// xAxis.enableGridDashedLine(10f, 10f, 0f);xAxis.position = XAxis.XAxisPosition.BOTTOMxAxis.axisLineWidth = resources.getDimension(R.dimen.tvcommon_px1)xAxis.axisLineColor = resources.getColor(R.color.color_979797)xAxis.textSize = resources.getDimension(R.dimen.tvcommon_sp16)xAxis.textColor = resources.getColor(R.color.white_60alpha)xAxis.valueFormatter = object : ValueFormatter() {override fun getAxisLabel(value: Float, axis: AxisBase?): String {// 自定义 X 轴显示内容return super.getAxisLabel(value, axis) + "月"}}// 3. Y轴样式mChart.axisRight.isEnabled = false  // disable dual axis (only use LEFT axis)var yAxis: YAxis = mChart.axisLeftyAxis.axisLineWidth = resources.getDimension(R.dimen.tvcommon_px1)yAxis.axisLineColor = resources.getColor(R.color.color_979797)yAxis.textSize = resources.getDimension(R.dimen.tvcommon_sp16)yAxis.textColor = resources.getColor(R.color.white_60alpha)yAxis.setDrawGridLines(true)        // horizontal grid linesyAxis.enableGridDashedLine(resources.getDimension(R.dimen.tvcommon_px6),resources.getDimension(R.dimen.tvcommon_px6),0f)yAxis.axisMaximum = 200fyAxis.axisMinimum = 0f
}

3.4 折线类型设置

需要在 填充数据时,给 LineDataSet 设置一个 mode,如下

private fun setChatData() {...val set1 = LineDataSet(values, "DataSet 1")set1.mode = LineDataSet.Mode.HORIZONTAL_BEZIER  // 折线类型
}

setMode(LineDataSet.Mode mode),设置模式有四种: 1.CUBIC_BEZIER 立方曲线 2.LINEAR 直线 3.STEPPED 阶梯 4.HORIZONTAL_BEZIER 水平曲线

电视项目这里需要的是一个曲线,所以设置为 HORIZONTAL_BEZIER

3.5 顶点设置

顶点可进行 icon 绘制、小圆点(实心/空心)、自定义值显示

private fun setChatData() {...val set1 = LineDataSet(values, "DataSet 1")set1.mode = LineDataSet.Mode.HORIZONTAL_BEZIER  // 折线类型// 顶点set1.setValueFormatter(object : ValueFormatter() {override fun getFormattedValue(value: Float): String {return "" // 这里返回空,即顶点不显示值,否则不太好看}})set1.valueTextSize = resources.getDimension(R.dimen.tvcommon_sp12)set1.setDrawIcons(false) // 不显示端点的iconset1.setDrawCircles(false) // 显示顶点圆quanset1.setDrawCircleHole(true) // 空心还是实心
}

3.6 折线及填充设置

private fun setChatData() {...// 折线set1.color = resources.getColor(R.color.blue_gray_32B5E6)set1.setCircleColor(resources.getColor(R.color.blue_gray_32B5E6))set1.lineWidth = resources.getDimension(R.dimen.tvcommon_px2)set1.circleRadius = resources.getDimension(R.dimen.tvcommon_px4)// 折线包裹起来的区域set1.fillFormatter = IFillFormatter { dataSet, dataProvider -> mChart.getAxisLeft().getAxisMinimum() }if (Utils.getSDKInt() >= 18) {// drawables only supported on api level 18 and aboveval drawable = ContextCompat.getDrawable(this, R.drawable.shape_chat_fill_blue)set1.fillDrawable = drawable} else {set1.fillColor = R.color.blue_gray_32B5E6}set1.setDrawFilled(true)
}

3.7 X 轴自定义显示 (非数据类型,在初始化时设置)

再回到 X 轴,由于项目要求,X 轴要显示节电的日期,但是构造数据时只是一个数组,默认显示的是数组的下标,所以这里需要自定义

private fun initChat() {... // 2. X 轴样式val xAxis: XAxis = mChart.getXAxis()...xAxis.valueFormatter = object : ValueFormatter() {override fun getAxisLabel(value: Float, axis: AxisBase?): String {// 自定义 X 轴显示内容,这里可以通过 axis 中的 postion 从数据中进行一个映射,找到它对应的日期return super.getAxisLabel(value, axis) + "月"}}
}

4. 踩坑及解决

4.1 宽度或 margin 跟自己设置的不一样

1. 效果出来后,发现最右侧不是我设置的,比我预计的靠左了,离边比较远,达不到 UI 设计的效果,如下:

2. 这里的设置应该不是通过简单的 XML 位置属性就能修改的了,因为这属于 MPAndroidChat 控件的内部了,所以得深入 MPAndroidChat,找到产生间隙的原因,于是开始翻源码

3. 经过翻阅源码得知,它内部有一个 minOffset

@Override
public void calculateOffsets() {...float minOffset = Utils.convertDpToPixel(mMinOffset);mViewPortHandler.restrainViewPort(Math.max(minOffset, offsetLeft),Math.max(minOffset, offsetTop),Math.max(minOffset, offsetRight),Math.max(minOffset, offsetBottom));...
}
public void setMinOffset(float minOffset) {mMinOffset = minOffset;
}

  再往下查,原来 mMinOffset,是可能通过 setMinOffset()设置进去的,所以在我们的代码 initChat()中添加上一行,再看效果,OK 啦~

private fun initChat() {...mChart.minOffset = 0f...
}

4.2 设置 x 轴的 Label 后,发现最底下一层有一点显示不全,被截断了,如下

1. 分析原因

(1)这个应该也是 MPAndroidChat 内部实现导致的,修改外部 Layout 中的 margin, padding 应该不生效,果然,试过之后,没有生效,问题依旧

(2)16sp 时显示是这个效果,而缩小字号后,比如 12sp, 就没有问题,能够显示,猜测,是它内部写死了一个距离,但看源码内的相关说明,它的高度是自动计算的,如下

/*** Class representing the x-axis labels settings. Only use the setter methods to* modify it. Do not access public variables directly. Be aware that not all* features the XLabels class provides are suitable for the RadarChart.** @author Philipp Jahoda*/
public class XAxis extends AxisBase {/*** width of the x-axis labels in pixels - this is automatically* calculated by the computeSize() methods in the renderers*/public int mLabelWidth = 1;/*** height of the x-axis labels in pixels - this is automatically* calculated by the computeSize() methods in the renderers*/public int mLabelHeight = 1;

(3)按理说不应该出现这种情况,难道是 MPAndroidChat 的 Bug,是不是高版本就好了呢,于是上网查了一下,https://gitee.com/jiangsongbai/MPAndroidChart, Github 打不开,到这里的一个 fork 上看一下,发现我用的已经是最新版了 v3.1.0 (吐槽:版本号竟然带个 v,看来不专业啊~)

(4)小插曲:由于项目中使用的是 dimen 中定义的 tvcommon_sp16,在不同分辨率下,可能不一样,我原先是写死的,抱着一点小希望,在代码中使用 dimen 试一下,期望字体能够变小一点,不触发此问题,结果又失望了

xAxis.textSize = resources.getDimension(R.dimen.tvcommon_sp16)

2. extraBottomOffset

(1)再翻阅源码,还是在 BarLineChatBase.java 中的 calculateOffsets() 函数,发现了端倪,如下:

@Override
public void calculateOffsets() {....offsetTop += getExtraTopOffset();offsetRight += getExtraRightOffset();offsetBottom += getExtraBottomOffset();offsetLeft += getExtraLeftOffset();float minOffset = Utils.convertDpToPixel(mMinOffset);mViewPortHandler.restrainViewPort(Math.max(minOffset, offsetLeft),Math.max(minOffset, offsetTop),Math.max(minOffset, offsetRight),Math.max(minOffset, offsetBottom));....
}

(2)这里有一个 getExtraBottomOffset(),再往下看,它是在基类 chat.java 中,有一个 mExtraBottomOffset,

/*** @return the extra offset to be appended to the viewport's bottom*/
public float getExtraBottomOffset() {return mExtraBottomOffset;
}

(3)看注释,像是有点用,尝试一下

private fun initChat() {....mChart.minOffset = 0fmChart.extraBottomOffset = resources.getDimension(R.dimen.tvcommon_px2) // 因为X轴的Label字体设为 16sp 后,最底下有一点显示不全,需要在这里打上一个小补丁。....
}

(4)大功告成~

4.3 顶点的数据显示想要隔位置显示效果

跟产品讨论的时候,把 UI 原先设计的选中点的值显示出来的效果去掉了(因为电视上没有触摸,通过遥控器交互暂时先不做选中效果),如果显示出来所有的数据,会显得比较凌乱,所以想进行隔几个显示或什么效果,研究后,发现重截函数中没有位置信息,无法进行计算是哪一个 postion,暂时无法做到不同的效果,只能统一显示或不显示,后续再进行深入研究,看是否能够做到

private fun setChatData() {...val set1 = LineDataSet(values, "DataSet 1")set1.mode = LineDataSet.Mode.HORIZONTAL_BEZIER  // 折线类型// 顶点set1.setValueFormatter(object : ValueFormatter() {override fun getFormattedValue(value: Float): String {return "" // 这里返回空,即顶点不显示值,否则不太好看}})...
}

5. 小结

这里记录了在电视项目中使用 MPAndroidChat 的一些使用心得,重点集中在折线上,通过对它的各种属性进行修改自定义了自己的 UI 界面,达到与 UI 设计图一样的效果,也发掘出了 minOffset、extraBottomOffset 这样的小众属性的使用场景及效果,希望能够引起大家的一些共鸣,发现问题时,快速找到解决方法。

6. 团队介绍

「三翼鸟数字化技术平台-场景设计交互平台」主要负责设计工具的研发,包括营销设计工具、家电VR设计和展示、水电暖通前置设计能力,研发并沉淀素材库,构建家居家装素材库,集成户型库、全品类产品库、设计方案库、生产工艺模型,打造基于户型和风格的AI设计能力,快速生成算量和报价;同时研发了门店设计师中心和项目中心,包括设计师管理能力和项目经理管理能力。实现了场景全生命周期管理,同时为水,空气,厨房等产业提供商机管理工具,从而实现了以场景贯穿的B端C端全流程系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/342597.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPS表格插件方方格子【凑数】功能:选出和等于固定数字的数

文章目录 后来发现可以下载方方格子插件&#xff0c;使用【凑数】功能https://ffcell.lanzouj.com/iwhfc1kjhayh【凑数】快速【凑数】 导师让沾发票&#xff0c;需要选出若干个数额的发票&#xff0c;使它们的和等于一个指定数。不知道怎么办了&#xff0c;查了一下&#xff0c…

Python第二语言(四、Python数据容器)

目录 一、 数据容器&#xff08;list、tuple、str、map、dict&#xff09; 1. 数据容器概念 2. 列表list&#xff08; [] &#xff09; 2.1 定义方式 2.2 嵌套列表 2.3 list通过获取下标索引获取值 2.4 下标使用概念 2.5 list列表的使用&#xff08;列表的方法&#xff…

linux nohup命令详解:持久运行命令,无视终端退出

nohup &#xff08;全称为 “no hang up”&#xff09;&#xff0c;用于运行一个命令&#xff0c;使其在你退出 shell 或终端会话后继续运行。 基本语法 nohup command [arg1 ...] [&> output_file] &command 是你想要运行的命令。[arg1 ...] 是该命令的参数。&am…

快排与归并的算法(非递归版)

一.快排 1.递归法(方法多样) 1>hoare版 注&#xff1a;该方法小编已经在上篇博客中介绍过了&#xff0c;就不在这里过多赘述了&#xff0c;如果有兴趣的小伙伴可以看看小编的上篇博客哦 2>挖坑法 1&#xff09;方法介绍&#xff1a;定义最左边的数据为key&#xff0…

生信学习入门常见错误可能的原因分类总结和求助指南

文件或目录找不到 这是常见问题&#xff0c;常见提示有 No such file or directory Error in file(file, “rt”)&#xff1a;无法打开链接 Fatal error: Unable to open file for reading (seq/WT1_1.fq) Fatal error: Unable to read from file (C:Program file/Git/usea…

OneDrive空间清理及文件历史版本查询

点击OneDrive图标 点击“在线查看” 点击“设置” 点击“OneDrive设置” 点击“其他设置” 点击“存储标准” 点击“文档” 选择需要操作的文件&#xff0c;点击“历史版本记录” 需要清理空间&#xff0c;可删除历史版本&#xff0c;需要使用历史版本&#xff0c;可还原历史版…

为什么我们需要在软件本地化过程中使用术语服务?

你知道软件翻译和本地化的术语服务吗&#xff1f;此解决方案涵盖源术语和目标术语的创建、开发和维护。所有术语都存储在具有多个字段的数据库中&#xff0c;包括术语定义、用法示例、上下文和历史记录。这使我们能够正确处理每个术语的创建或更改请求&#xff0c;避免创建重复…

f1c100s 荔枝派 系统移植

一。交叉编译环境配置 1.1下载交叉工具链&#xff1a;https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11/arm-linux-gnueabi/ 1.2解压安装 在home目录下新建 工程目录&#xff1a;mkdir f1c100s_project 将windows下的gcc-linaro-7.2.1-2017.11-x86…

Spark MLlib 机器学习详解

目录 &#x1f349;引言 &#x1f349;Spark MLlib 简介 &#x1f348; 主要特点 &#x1f348;常见应用场景 &#x1f349;安装与配置 &#x1f349;数据处理与准备 &#x1f348;加载数据 &#x1f348;数据预处理 &#x1f349;分类模型 &#x1f348;逻辑回归 &a…

C# FTP/SFTP 详解及连接 FTP/SFTP 方式示例汇总

文章目录 1、FTP/SFTP基础知识FTPSFTP 2、FTP连接示例3、SFTP连接示例4、总结 在软件开发中&#xff0c;文件传输是一个常见的需求。尤其是在不同的服务器之间传输文件时&#xff0c;FTP&#xff08;文件传输协议&#xff09;和SFTP&#xff08;安全文件传输协议&#xff09;成…

前端图片在切换暗黑模式时太亮该怎么办?

通过css中的filter属性来实现&#xff0c;进行图片的色系反转、亮度、对比度调整等 1、invert 反转输入图像&#xff0c;值为 100% 则图像完全反转&#xff0c;值为 0% 则图像无变化 filter: invert(1); 2、blur 给元素应用高斯模糊效果。 filter: blur(5px); 3、brightnes…

C++设计模式-外观模式,游戏引擎管理多个子系统,反汇编

运行在VS2022&#xff0c;x86&#xff0c;Debug下。 30. 外观模式 为子系统定义一组统一的接口&#xff0c;这个高级接口会让子系统更容易被使用。应用&#xff1a;如在游戏开发中&#xff0c;游戏引擎包含多个子系统&#xff0c;如物理、渲染、粒子、UI、音频等。可以使用外观…

Xcode 打包报错Command PhaseScriptExecution failed with a nonzero exit code

解决办法: 1、在Xcode项目中 Pods -> Targets Support Files -> Pods-项目名 -> Pods-项目名-frameworks 中(大约在第44行) 加上 -f 2、CocoaPods版本太旧了,可以尝试升级CocoaPods版本 使用sudo gem update cocoapods更新cocoapods&#xff0c;问题将在1.12.1版本已…

DP读书:如何使用badge?(开源项目下的标咋用)

最近在冲论坛&#xff0c;很少更一些内容了。但遇到了一个真的有趣的&#xff1a; 开源项目下&#xff0c;蓝蓝绿绿的标是怎么用的呢&#xff1f; 这是我的主页Readme&#xff0c;在看一些NXP的主仓时&#xff0c;突然发现没有这个玩&#xff0c;就自己整了个 再比如我的CSDN专…

信号:干扰类别及特征提取

目录 第一部分&#xff1a;干扰类别 1.压制干扰 1.1噪声调幅瞄准式干扰(单音干扰) 1.2噪声调频阻塞式干扰&#xff08;宽带噪声干扰&#xff09; 1.3噪声调频扫频式干扰&#xff08;线性调频&#xff09; 2.欺骗干扰 2.1距离欺骗干扰&#xff08;幅度调制干扰&#xff0…

MySQL—多表查询—内连接

一、引言 &#xff08;1&#xff09;内连接查询语法 内连接查询的是两张表的交集部分的数据。&#xff08;也就是绿色部分展示的数据&#xff09; &#xff08;2&#xff09;内连接有两种形式&#xff1a; 1、隐式内连接 语法结构&#xff1a; 2、显示内连接 语法结构&#xf…

上市即交付,比亚迪秦L DM-i万人交车暨千媒众测开营

6月6日&#xff0c;“引领中级 开创油耗2时代”秦L DM-i万人交车暨千媒众测开营仪式在比亚迪大本营深圳盛大举行。 众多车主代表亲临现场&#xff0c;与全国各地的比亚迪4S店千店联动&#xff0c;将秦L DM-i全国交付推向新的高潮。发布即量产&#xff0c;上市即交付&#xff0…

查看远程桌面端口,查看服务器的远程桌面端口的方法

如果你正在寻找一种方法来检查服务器的远程桌面端口&#xff0c;那么请务必按照以下步骤操作&#xff0c;以确保准确且安全地获取所需信息。这不仅是一个技术问题&#xff0c;更是一个关于效率和安全性的重要议题。 首先&#xff0c;你需要明确&#xff0c;远程桌面端口通常是…

SQLServer 查询指定数据库名和表名及表结构等

查询当前数据库中所有表名&#xff0c;不用指定数据库&#xff0c;选中某数据库直接执行SQL就好 -- U:所有用户表名; S:所有系统表名;V:所有视图表名 SELECT name FROM sysobjects WHERE xtypeU OR xtypeS OR xtypeV 查询指定数据库数据库中所有表名&#xff0c; SELECT TAB…

【西瓜书】4.决策树

1 递归返回情况 &#xff08;1&#xff09;结点包含样本全为同一类别 &#xff08;2&#xff09;属性集为空&#xff0c;没有属性可供划分了 或 有属性&#xff0c;但是在属性上划分的结果都一样 &#xff08;3&#xff09;结点为空结点 **结束时判定该结点的类别遵循如下规则&…