MPAndroidChart LineChart 折线图 你要的都在这里了
前言
??MPAndroidChart已經(jīng)出了很長的一段時間,相信大家也有所耳聞,自己也使用了有一段時間,固在此寫下文章,根據(jù)項目的需求,記錄一些見解與問題,作為參考。望大家取其精華去其糟粕。
最終效果圖
涉及到的問題以及知識點
圖表樣式以及基礎(chǔ)數(shù)據(jù) (快速入門)
x軸標(biāo)簽自定義標(biāo)簽(Formatting Data Values (ValueFormatter))
自定義覆蓋物(MarkerView)
自定義多個覆蓋物(MarkerView)
默認(rèn)選中覆蓋物(Highlighting Values)
線條的隱藏以及顯示(visible)
實現(xiàn)左右滑動
數(shù)據(jù)更新
當(dāng)前演示 Demo
快速入門
1.編寫布局文件
?<com.github.mikephil.charting.charts.LineChart
? ? ? ? android:id="@+id/chart"
? ? ? ? android:layout_width="match_parent"
? ? ? ? android:layout_height="195dp"
? ? ? ? />
2.實例化并且,設(shè)置x軸和y軸的點
mLineChart = findViewById(R.id.chart);
//1.設(shè)置x軸和y軸的點
List<Entry> entries = new ArrayList<>();
? ?for (int i = 0; i < 12; i++)
? ? ? entries.add(new Entry(i, new Random().nextInt(300)));
3 .把數(shù)據(jù)賦值到你的線條
? LineDataSet dataSet = new LineDataSet(entries, "Label"); // add entries to dataset
4.設(shè)置數(shù)據(jù)刷新圖表
//3.chart設(shè)置數(shù)據(jù)
? LineData lineData = new LineData(dataSet);
? mLineChart.setData(lineData);
? mLineChart.invalidate(); // refresh
?
很簡單吧,但是離我們的效果圖還差了好多現(xiàn)在我們開始完善樣式,一步一步去設(shè)置
樣式設(shè)置
1.線條樣式
? ? ? ? LineDataSet dataSet = new LineDataSet(entries, "Label"); // add entries to dataset
? ? ? ? dataSet.setColor(Color.parseColor("#7d7d7d"));//線條顏色
? ? ? ? dataSet.setCircleColor(Color.parseColor("#7d7d7d"));//圓點顏色
? ? ? ? dataSet.setLineWidth(1f);//線條寬度
2.x和y軸樣式
? ? ? ? //設(shè)置樣式
? ? ? ? YAxis rightAxis = mLineChart.getAxisRight();
? ? ? ? //設(shè)置圖表右邊的y軸禁用
? ? ? ? rightAxis.setEnabled(false);
? ? ? ? YAxis leftAxis = mLineChart.getAxisLeft();
? ? ? ? //設(shè)置圖表左邊的y軸禁用
? ? ? ? leftAxis.setEnabled(false);
? ? ? ? //設(shè)置x軸
? ? ? ? XAxis xAxis = mLineChart.getXAxis();
? ? ? ? xAxis.setTextColor(Color.parseColor("#333333"));
? ? ? ? xAxis.setTextSize(11f);
? ? ? ? xAxis.setAxisMinimum(0f);
? ? ? ? xAxis.setDrawAxisLine(true);//是否繪制軸線
? ? ? ? xAxis.setDrawGridLines(false);//設(shè)置x軸上每個點對應(yīng)的線
? ? ? ? xAxis.setDrawLabels(true);//繪制標(biāo)簽 ?指x軸上的對應(yīng)數(shù)值
? ? ? ? xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);//設(shè)置x軸的顯示位置
? ? ? ? xAxis.setGranularity(1f);//禁止放大后x軸標(biāo)簽重繪
3.隱藏圖例與描述
? ? ? ? //透明化圖例
? ? ? ? Legend legend = mLineChart.getLegend();
? ? ? ? legend.setForm(Legend.LegendForm.NONE);
? ? ? ? legend.setTextColor(Color.WHITE);
? ? ? ? //隱藏x軸描述
? ? ? ? Description description = new Description();
? ? ? ? description.setEnabled(false);
? ? ? ? mLineChart.setDescription(description);
4.填充數(shù)據(jù)
? ? ? ? //chart設(shè)置數(shù)據(jù)
? ? ? ? LineData lineData = new LineData(dataSet);
? ? ? ? //是否繪制線條上的文字
? ? ? ? lineData.setDrawValues(false);
? ? ? ? mLineChart.setData(lineData);
? ? ? ? mLineChart.invalidate(); // refresh
效果圖?
是不是已經(jīng)很接近效果圖了,我們在格式化一下x軸標(biāo)簽
x軸標(biāo)簽自定義標(biāo)簽(Formatting Data Values (ValueFormatter))
格式化x軸標(biāo)簽有好幾種方式,這里說兩個方法?
1.要么自己實現(xiàn)接口的方式
?XAxis xAxis = mLineChart.getXAxis();
?xAxis.setValueFormatter(new IAxisValueFormatter() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public String getFormattedValue(float value, AxisBase axis) {
? ? ? ? ? ? ? ? return String.valueOf((int) value + 1).concat("月");
? ? ? ? ? ? }
? ? ? ? });
2.要么用庫已經(jīng)寫好的類
//準(zhǔn)備好每個點對應(yīng)的x軸數(shù)值
List<String> list = new ArrayList<>();
?for (int i = 0; i < 12; i++) {
? ? ?list.add(String.valueOf(i+1).concat("月"));
?}
? XAxis xAxis = mLineChart.getXAxis();
?xAxis.setValueFormatter(new IndexAxisValueFormatter(list));
格式化Y軸也是同樣的道理
效果圖?
自定義覆蓋物(MarkerView)
(1) 繼承MarkerView復(fù)寫其中的方法就OJBK了
直接上代碼解釋吧 -v-
public class DetailsMarkerView extends MarkerView {
? ? private TextView mTvMonth;
? ? private TextView mTvChart1;
? ? /**
? ? ?* 在構(gòu)造方法里面?zhèn)魅胱约旱牟季忠约皩嵗丶?? ?
? ? ?* @param context 上下文
? ? ?* @param 自己的布局?
? ?*/
? ? public DetailsMarkerView(Context context, int layoutResource) {
? ? ? ? super(context, layoutResource);
? ? ? ? mTvMonth = findViewById(R.id.tv_chart_month);
? ? ? ? mTvChart1 = findViewById(R.id.tv_chart_1);
? ? }
? ? //每次重繪,會調(diào)用此方法刷新數(shù)據(jù)
? ? @Override
? ? public void refreshContent(Entry e, Highlight highlight) {
? ? ? ? super.refreshContent(e, highlight);
? ? ? ? try {
? ? ? ? ? ? //收入
? ? ? ? ? ? if (e.getY() == 0) {
? ? ? ? ? ? ? ? mTvChart1.setText("暫無數(shù)據(jù)");
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? mTvChart1.setText(concat(e.getY(), "支出:"));
? ? ? ? ? ? }
? ? ? ? ? ? mTvMonth.setText(String.valueOf((int) e.getX() + 1).concat("月"));
? ? ? ? } catch (Exception e1) {
? ? ? ? ? ? e1.printStackTrace();
? ? ? ? }
? ? ? ? super.refreshContent(e, highlight);
? ? }
? ? //布局的偏移量。就是布局顯示在圓點的那個位置
? ? // -(width / 2) 布局水平居中
? ? //-(height) 布局顯示在圓點上方
? ? @Override
? ? public MPPointF getOffset() {
? ? ? ? return new MPPointF(-(getWidth() / 2), -getHeight());
? ? }
? ? public String concat(float money, String values) {
? ? ? ? return values + new BigDecimal(money).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "元";
? ? }
}
(2) 設(shè)置覆蓋物
DetailsMarkerView detailsMarkerView = new DetailsMarkerView(this);
//一定要設(shè)置這個玩意,不然到點擊到最邊緣的時候不會自動調(diào)整布局
detailsMarkerView.setChartView(mLineChart);
mLineChart.setDetailsMarkerView(detailsMarkerView);
效果圖
自定義多個覆蓋物(MarkerView)
接下來我們繼續(xù)完善,達到下面的效果圖
要達到上面的效果,我們可以把它當(dāng)作3個覆蓋物?
就是這個意思?
1.先定義好3個覆蓋物,DetailsMarkerView(詳情),PositionMarker (中間的標(biāo)桿)RoundMarker(圓點)
class DetailsMarkerView ?extends MarkerView{...}
class PositionMarker ?extends MarkerView{...}
class RoundMarkerextends MarkerView{...}
1
2
3
2.繼承LineChart,重寫drawMarkers 方法。我們直接把drawMarkers方法直接復(fù)制下來,加上自己所需要的MarkerView,然后計算它們的位置即可
public class MyLineChart extends LineChart {
? ? ? //弱引用覆蓋物對象,防止內(nèi)存泄漏,不被回收
? ? private WeakReference<DetailsMarkerView> mDetailsReference;
? ? private WeakReference<RoundMarker> mRoundMarkerReference;
? ? private WeakReference<PositionMarker> mPositionMarkerReference;
? ? /**
? ? ?* 所有覆蓋物是否為空
? ? ?*
? ? ?* @return TRUE FALSE
? ? ?*/
? ? public boolean isMarkerAllNull() {
? ? ? ? return mDetailsReference.get() == null && mRoundMarkerReference.get() == null && mPositionMarkerReference.get() == null;
? ? }
? ? public void setDetailsMarkerView(DetailsMarkerView detailsMarkerView) {
? ? ? ? mDetailsReference = new WeakReference<>(detailsMarkerView);
? ? }
? ? public void setRoundMarker(RoundMarker roundMarker) {
? ? ? ? mRoundMarkerReference = new WeakReference<>(roundMarker);
? ? }
? ? public void setPositionMarker(PositionMarker positionMarker) {
? ? ? ? mPositionMarkerReference = new WeakReference<>(positionMarker);
? ? }
? ?/**
? ? ? 復(fù)制父類的 drawMarkers方法,并且更換上自己的markerView
? ? ?* draws all MarkerViews on the highlighted positions
? ? ?*/
? ? protected void drawMarkers(Canvas canvas) {
? ? ? ? DetailsMarkerView mDetailsMarkerView = mDetailsReference.get();
? ? ? ? RoundMarker mRoundMarker = mRoundMarkerReference.get();
? ? ? ? PositionMarker mPositionMarker = mPositionMarkerReference.get();
? ? ? ? // if there is no marker view or drawing marker is disabled
? ? ? ? if (mDetailsMarkerView == null || mRoundMarker == null || mPositionMarker == null || !isDrawMarkersEnabled() || !valuesToHighlight())
? ? ? ? ? ? return;
? ? ? ? for (int i = 0; i < mIndicesToHighlight.length; i++) {
? ? ? ? ? ? Highlight highlight = mIndicesToHighlight[i];
? ? ? ? ? ? IDataSet set = mData.getDataSetByIndex(highlight.getDataSetIndex());
? ? ? ? ? ? Entry e = mData.getEntryForHighlight(mIndicesToHighlight[i]);
? ? ? ? ? ? int entryIndex = set.getEntryIndex(e);
? ? ? ? ? ? // make sure entry not null
? ? ? ? ? ? if (e == null || entryIndex > set.getEntryCount() * mAnimator.getPhaseX())
? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? float[] pos = getMarkerPosition(highlight);
? ? ? ? ? ? LineDataSet dataSetByIndex = (LineDataSet) getLineData().getDataSetByIndex(highlight.getDataSetIndex());
? ? ? ? ? ? // check bounds
? ? ? ? ? ? if (!mViewPortHandler.isInBounds(pos[0], pos[1]))
? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? float circleRadius = dataSetByIndex.getCircleRadius();
? ? ? ? ? ? //pos[0], pos[1] x 和 y?
? ? ? ? ? ? // callbacks to update the content
? ? ? ? ? ? mDetailsMarkerView.refreshContent(e, highlight);
? ? ? ? ? ? mDetailsMarkerView.draw(canvas, pos[0], pos[1] - mPositionMarker.getHeight());
? ? ? ? ? ? mPositionMarker.refreshContent(e, highlight);
? ? ? ? ? ? mPositionMarker.draw(canvas, pos[0] - mPositionMarker.getWidth() / 2, pos[1] - mPositionMarkerl.getHeight());
? ? ? ? ? ? mRoundMarker.refreshContent(e, highlight);
? ? ? ? ? ? mRoundMarker.draw(canvas, pos[0] - mRoundMarker.getWidth() / 2, pos[1] + circleRadius - mRoundMarker.getHeight());
? ? ? ? }
}
設(shè)置覆蓋物 activity主要代碼
protected void onCreate(Bundle savedInstanceState) {
? ? ......
? ? //點擊圖表坐標(biāo)監(jiān)聽
? ? ? ? mLineChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onValueSelected(Entry e, Highlight h) {
? ? ? ? ? ? ? ? //查看覆蓋物是否被回收
? ? ? ? ? ? ? ? if (mLineChart.isMarkerAllNull()) {
? ? ? ? ? ? ? ? ? ? //重新綁定覆蓋物
? ? ? ? ? ? ? ? ? ? createMakerView();
? ? ? ? ? ? ? ? ? ? //并且手動高亮覆蓋物
? ? ? ? ? ? ? ? ? ? mLineChart.highlightValue(h);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onNothingSelected() {
? ? ? ? ? ? }
? ? ? ? });
? ? ......
}
? /**
? ? * 創(chuàng)建覆蓋物
? ? */
? ?public void createMakerView() {
? ? ? ?DetailsMarkerView detailsMarkerView = new DetailsMarkerView(this);
? ? ? ?detailsMarkerView.setChartView(mLineChart);
? ? ? ?mLineChart.setDetailsMarkerView(detailsMarkerView);
? ? ? ?mLineChart.setPositionMarker(new PositionMarker(this));
? ? ? ?mLineChart.setRoundMarker(new RoundMarker(this));
? ?}
這樣就大功告成啦!!
默認(rèn)顯示覆蓋物(Highlighting Values)
可以通過上面的方法,默認(rèn)顯示覆蓋物,比如
? ?//默認(rèn)顯示第一個覆蓋物
? ?mLineChart.highlightValue(0,0);
1
2
線條的隱藏以及顯示(Highlighting Values)
可以通過LineChart對象獲取到線條LineDataSet實體類。然后調(diào)用LineDataSet.setVisible(true或者false);,進行隱藏或顯示
mLineChart.getLineData().getDataSets().get(0).setVisible(true);
1
左右滑動,并動態(tài)切換放大倍數(shù)
代碼
//x放大5倍 ?1f代表不放大
mLineChart.zoomToCenter(5, 1f);
//切記如果要動態(tài)的更換倍數(shù),或者還原倍數(shù)一定要調(diào)用下面的這個方法停止慣性滑動
//不然在拖動過程當(dāng)中是無法更換倍數(shù)
BarLineChartTouchListener barLineChartTouchListener = (BarLineChartTouchListener) mLineChart.getOnTouchListener();
?barLineChartTouchListener.stopDeceleration();
更新數(shù)據(jù)
主要的邏輯:?
1. 準(zhǔn)備要更新的數(shù)據(jù)源?
2. 檢查是否有LineDataSet 存在?
3. 有,則通過LineDataSet 的setValues更換整個坐標(biāo),或者 data.addEntry(…) 添加一個或者 data.removeEntry(…)刪除一個。?
4. 無,則創(chuàng)建LineDataSet ,重新構(gòu)造數(shù)據(jù)源?
4. 調(diào)用mLineChart.invalidate();更新圖表
代碼實例:
?//1,準(zhǔn)備要更換的數(shù)據(jù)
? ? ?List<Entry> entries = new ArrayList<>();
? ? ? ? for (int i = 0; i < 12; i++)
? ? ? ? ? ? entries.add(new Entry(i, new Random().nextInt(300)));
? ? ? ? //2. 獲取LineDataSet線條數(shù)據(jù)集
? ? ? ? List<ILineDataSet> dataSets = mLineChart.getLineData().getDataSets();
? ? ? ?//是否存在
? ? ? ? ?if (dataSets != null && dataSets.size() > 0) {
? ? ? ? ? ? ?//直接更換數(shù)據(jù)源
? ? ? ? ? ? ?for (ILineDataSet set : dataSets) {
? ? ? ? ? ? ? ? ?LineDataSet data = (LineDataSet) set;
? ? ? ? ? ? ? ? ?data.setValues(entries);
? ? ? ? ? ? ?}
? ? ? ? ?} else {
? ? ? ? ? ? ?//重新生成LineDataSet線條數(shù)據(jù)集
? ? ? ? ? ? ?LineDataSet dataSet = new LineDataSet(entries, "Label"); // add entries to dataset
? ? ? ? ? ? dataSet.setDrawCircles(false);
? ? ? ? ? ? ? ?dataSet.setColor(Color.parseColor("#7d7d7d"));//線條顏色
? ? ? ? ? ? ? ?dataSet.setCircleColor(Color.parseColor("#7d7d7d"));//圓點顏色
? ? ? ? ? ? ? ?dataSet.setLineWidth(1f);//線條寬度
? ? ? ? ? ? ? ?LineData lineData = new LineData(dataSet);
? ? ? ? ? ? ? ?//是否繪制線條上的文字
? ? ? ? ? ? ? ?lineData.setDrawValues(false);
? ? ? ? ? ? ? ?mLineChart.setData(lineData);
? ? ? ? ? ?}
? ? ? ? ? ?//更新
? ? ? ? ? ?mLineChart.invalidate();
完
?
總結(jié)
以上是生活随笔為你收集整理的MPAndroidChart LineChart 折线图 你要的都在这里了的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多媒体音频格式解析WMA WAV OGG
- 下一篇: android sina oauth2.