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.pswp.cn/bicheng/19589.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/19589.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/19589.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【力扣】LCR 130. 衣櫥整理

一、題目描述 二、算法思路 這是?道非常典型的「搜索」類問題。 我們可以通過「深搜」或者「寬搜」&#xff0c;從 [0, 0] 點出發&#xff0c;按照題目的要求&#xff08;選擇 向右移動一格 或 向下移動一格&#xff0c;但不能移動到衣柜之外 &#xff09;一直往 [m - 1, …

詳解Spring IoCDI(二)

目錄 承接上文&#xff1a;詳解Spring IoC&DI &#xff08;一&#xff09; 1.IoC詳解 1.1方法注解Bean 1.2方法注解要配合類注解使用 1.3定義多個對象 1.4重命名Bean 1.5掃描路徑 2.DI詳解 2.1DI與IoC的關系 2.2屬性注入 2.3構造方法注入 2.4Setter注入 2.5 三…

代碼隨想錄算法訓練營第四十五天|1049.最后一塊石頭的重量II、494.目標和、 474.一和零

1049.最后一塊石頭的重量II 文檔講解&#xff1a;代碼隨想錄 題目鏈接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 本題其實就是盡量讓石頭分成重量相同的兩堆&#xff0c;相撞之后剩下的石頭最小&#xff0c;這樣就化解成01背包問題了。 和昨天講解的416. 分割等和…

visual studio code 全局搜索

VScode寫代碼的時候&#xff0c;會經常性的需要進行查找代碼&#xff0c;那么怎么在Visual Studio Code中進行查找呢&#xff0c;下面就來大家vscode全局搜索的方法。 想要在vscode全局搜索進行全局搜索&#xff0c;使用快捷鍵CTRLSHIFTF即可進行搜索&#xff0c;也可以在左邊…

哪吒監控+cfcdn+ 反代grp端口

哪吒監控cfcdn 反代grp端口 背景&#xff1a; 哪吒監控&#xff1a;感覺VPS線路不穩定&#xff0c;為了打消自己潛意識&#xff0c;希望量化延遲。 cfcdn&#xff1a;隱藏真實站點&#xff0c;保障小雞隱秘安全 反代grpc端口: 反代grpc到支持https(TLS)的端口&#xff0c;這…

Tomcat啟動閃退問題及解決方法

Tomcat啟動閃退問題可能由多種原因引起&#xff0c;以下是一些常見的原因及相應的解決方法&#xff0c;按照清晰的結構進行歸納&#xff1a; 一、環境變量問題 Java環境問題&#xff1a;Tomcat依賴于Java環境&#xff0c;如果JDK未正確安裝或環境變量配置不正確&#xff0c;會…

Elasticsearch 認證模擬題 - 3

1、題目 有一索引有 3 個字段&#xff0c;請寫一個查詢去匹配這三個字段&#xff0c;并且將三個字段的評分相加作為最后的總評分 # 創建索引 PUT task {"mappings": {"properties": {"fielda":{"type": "text"},"fie…

TrueNAS開啟SSH登錄ROOT

簡介: 從 SCALE Bluefin 22.12.0 開始,為了加強安全性并遵守聯邦信息處理標準 (FIPS),root帳戶登錄已被棄用。所有 TrueNAS 用戶都應創建具有所有必需權限的本地管理員帳戶,并開始使用它來訪問 TrueNAS。當根用戶密碼被禁用時,只有管理用戶帳戶才能登錄 TrueNAS Web 界面。…

從零學算法2965

2965. 找出缺失和重復的數字 給你一個下標從 0 開始的二維整數矩陣 grid&#xff0c;大小為 n * n &#xff0c;其中的值在 [1, n2] 范圍內。除了 a 出現 兩次&#xff0c;b 缺失 之外&#xff0c;每個整數都 恰好出現一次 。 任務是找出重復的數字a 和缺失的數字 b 。 返回一個…

輪狀病毒簡介-卡梅德生物

輪狀病毒是一種非常常見的病毒&#xff0c;主要影響嬰幼兒和小孩&#xff0c;引起嚴重的胃腸炎&#xff0c;表現為嚴重腹瀉、嘔吐、發燒和脫水。這種病毒全球流行&#xff0c;是全世界五歲以下兒童因腹瀉導致死亡的主要原因之一。輪狀病毒屬于Reoviridae家族&#xff0c;具有雙…

邏輯回歸【python,機器學習,算法】

邏輯回歸是一種有監督的學習分類算法&#xff0c;用于預測目標變量的概率。目標或因變量的性質是二分法的&#xff0c;這意味著將只有兩個可能的類。主要解決二分類問題。 主要步驟有三個&#xff1a; 求線性回歸曲線。通過 sigmoid 函數將線性回歸曲線轉為 0-1 范圍函數。 …

機器學習-11-使用kaggle命令下載數據集和操作指南

參考kaggle API 命令下載數據集 參考Kaggle操作完整指南(2023版) 參考Kaggle如何入門? 1 kaggle操作指南 Kaggle 是一個流行的數據科學競賽平臺。由 Goldbloom 和 Ben Hamner 創建于 2010 年。為什么這兩個家伙要創立這樣一個平臺呢? 數據科學社區一直有這樣一個難題:對…

低代碼開發平臺(Low-code Development Platform)的模塊組成部分

低代碼開發平臺&#xff08;Low-code Development Platform&#xff09;的模塊組成部分主要包括以下幾個方面&#xff1a; 低代碼開發平臺的模塊組成部分可以按照包含系統、模塊、菜單組織操作行為等維度進行詳細闡述。以下是從這些方面對平臺模塊組成部分的說明&#xff1a; …

docker安裝mysql8和mysql5.7

1.docker安裝mysql5.7,請點擊此鏈接 2.docker安裝mysql8并掛載數據卷 docker pull mysql:8.0 docker run --name mysql8 -e MYSQL_ROOT_PASSWORDmy-secret-pw -d mysql:8.0 docker run --name mysql8 -e MYSQL_ROOT_PASSWORD123456 -v /mqq/mysql8/datadir:/var/lib/mysql -d…

虛擬dom的理解

由普通的js對象來描述dom對象&#xff0c;是對于真實dom的映射&#xff0c;因為不是真實的dom對象所以叫虛擬dom。因為js處理數據的速度比操作dom的速度更快&#xff0c;性能更好&#xff0c;所以讓現代這些react vue 等框架都采用了虛擬dom。 key值是唯一性的,在虛擬dom樹進行…

【喜報】科大睿智服務企業通過CMMI3級認證

?北京建投科信科技發展股份有限公司&#xff08;以下簡稱“北京建投科技” &#xff09;前身為北京銀帝科技發展公司&#xff0c;成立于1993年&#xff0c;注冊資本6,000萬元&#xff0c;為中國建銀投資有限責任公司&#xff08;簡稱“中國建投”&#xff09;的成員企業建投華…

現在,所有人都能免費用GPT-4o了!

OpenAI今日官宣&#xff0c;ChatGPT正式向所有用戶免費開放&#xff01;所有用戶均可以訪問定制化GPT、分析圖表、詢問有關照片的問題以及5月初GPT-4o添加的其他功能。 OpenAI今天在X上發布推文&#xff1a; 「所有ChatGPT免費用戶現在都可以使用瀏覽、視覺、數據分析、文件上…

element table表格行列合并span-method,根據數據動態行列合并

表格行列合并需要用到 table的方法 span-method 根據數據來進行動態的行列合并&#xff0c;實例如下&#xff1a; <el-table:data"tableData":span-method"objectSpanMethod" style"width: 100%"><el-table-columnprop"key"l…

mac電腦生成文件下載URL

1.首先打開web共享&#xff0c;終端方式。 開始 sudo apachectl start 停止&#xff1a; sudo apachectl stop 重啟&#xff1a; sudo apachectl restart 2.將需要下載的文件 app.v1.6.12_note.apk /Library/WebServer/Documents/ 目錄下 3. 同一網絡下&#xff0c;直接用…

C++系列——————類和對象(上)

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、面向對象的三大特征二、類的引入2.1類的定義 三.類的訪問限定符3.1訪問限定符的介紹3.2.訪問限定符的使用 四、類的作用域五、類的實例化六、類對象模型6.1…