首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

MPAndroidChart 開源圖表庫實戰:餅圖、折線圖、柱狀圖完整指南

     編輯:Java 相關知識

庫簡介與整合

MPAndroidChart 是 Android 平台最流行的開源圖表庫,支援線圖、餅圖、柱狀圖、散點圖、燭台圖、雷達圖等,提供拖拽縮放、動畫、圖例、標記等豐富交互功能。

依賴配置

// build.gradle (Module: app)
dependencies {
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
    // 或下載 jar 放入 libs 目錄
}

需在專案級 build.gradle 添加 JitPack 倉庫:

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

餅狀圖實現

XML 佈局

<com.github.mikephil.charting.charts.PieChart
    android:id="@+id/spread_pie_chart"
    android:layout_width="match_parent"
    android:layout_height="300dp" />

核心代碼


public class PieChartActivity extends AppCompatActivity {
    private PieChart mChart;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pie_chart);
        mChart = findViewById(R.id.spread_pie_chart);
        
        PieData pieData = getPieData(4, 100);
        showChart(mChart, pieData);
    }

    private void showChart(PieChart pieChart, PieData pieData) {
        // 基礎外觀
        pieChart.setHoleColorTransparent(true);
        pieChart.setHoleRadius(60f);           // 中心空洞半徑
        pieChart.setTransparentCircleRadius(64f); // 透明圈半徑
        pieChart.setDescription("2024 季度營收分布");
        pieChart.setDrawCenterText(true);
        pieChart.setCenterText("季度營收");      // 中心文字
        pieChart.setDrawHoleEnabled(true);
        pieChart.setRotationAngle(90);          // 起始旋轉角度
        pieChart.setRotationEnabled(true);      // 允許手勢旋轉
        pieChart.setUsePercentValues(true);     // 顯示百分比
        
        // 圖例配置
        Legend legend = pieChart.getLegend();
        legend.setPosition(Legend.LegendPosition.RIGHT_OF_CHART);
        legend.setXEntrySpace(7f);
        legend.setYEntrySpace(5f);
        
        // 動畫
        pieChart.animateXY(1000, 1000);
        
        pieChart.setData(pieData);
        pieChart.invalidate(); // 重繪
    }

    private PieData getPieData(int count, float range) {
        List xValues = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            xValues.add("Q" + (i + 1)); // 標籤
        }

        List yValues = new ArrayList<>();
        // 模擬數據:四季度佔比
        yValues.add(new PieEntry(14f, 0)); // 14%
        yValues.add(new PieEntry(14f, 1));
        yValues.add(new PieEntry(34f, 2));
        yValues.add(new PieEntry(38f, 3));

        PieDataSet dataSet = new PieDataSet(yValues, "2024 季度營收");
        dataSet.setSliceSpace(3f); // 扇區間距
        dataSet.setSelectionShift(5f); // 選中突出距離
        
        // 自定義顏色
        List colors = Arrays.asList(
            Color.rgb(205, 205, 205),
            Color.rgb(114, 188, 223),
            Color.rgb(255, 123, 124),
            Color.rgb(57, 135, 200)
        );
        dataSet.setColors(colors);
        
        // 數值格式化
        dataSet.setValueFormatter(new PercentFormatter(pieChart));
        dataSet.setValueTextSize(12f);
        dataSet.setValueTextColor(Color.WHITE);
        
        return new PieData(xValues, dataSet);
    }
}

折線圖實現

XML 佈局

<com.github.mikephil.charting.charts.LineChart
    android:id="@+id/spread_line_chart"
    android:layout_width="match_parent"
    android:layout_height="300dp" />

核心代碼


public class LineChartActivity extends AppCompatActivity {
    private LineChart mLineChart;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_line_chart);
        mLineChart = findViewById(R.id.spread_line_chart);
        
        LineData lineData = getLineData(30, 100); // 30個點
        showChart(mLineChart, lineData, Color.rgb(114, 188, 223));
    }

    private void showChart(LineChart chart, LineData data, int color) {
        chart.setDrawBorders(false);
        chart.setDescription("");
        chart.setNoDataTextDescription("暫無數據");
        chart.setDrawGridBackground(false);
        chart.setGridBackgroundColor(Color.WHITE & 0x70FFFFFF);
        
        // 交互啟用
        chart.setTouchEnabled(true);
        chart.setDragEnabled(true);
        chart.setScaleEnabled(true);
        chart.setPinchZoom(false);
        
        // 圖例
        Legend legend = chart.getLegend();
        legend.setForm(Legend.LegendForm.CIRCLE);
        legend.setFormSize(6f);
        legend.setTextColor(Color.WHITE);
        
        chart.setData(data);
        chart.animateX(2500); // X軸動畫
        chart.invalidate();
    }

    private LineData getLineData(int count, float range) {
        List xValues = new ArrayList<>();
        for (int i = 0; i < count; i++) xValues.add("" + i);

        List yValues = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            float val = (float) (Math.random() * range) + 3;
            yValues.add(new Entry(i, val)); // x 為索引
        }

        LineDataSet dataSet = new LineDataSet(yValues, "測試折線圖");
        dataSet.setLineWidth(2f);
        dataSet.setCircleRadius(3f);
        dataSet.setColor(Color.WHITE);
        dataSet.setCircleColor(Color.WHITE);
        dataSet.setHighLightColor(Color.rgb(255, 255, 0));
        dataSet.setDrawValues(true); // 顯示數值
        dataSet.setValueTextSize(10f);
        
        // 填充區域
        dataSet.setDrawFilled(true);
        dataSet.setFillColor(Color.rgb(114, 188, 223));
        dataSet.setFillAlpha(80);
        
        return new LineData(xValues, dataSet);
    }
}

柱狀圖實現

XML 佈局

<com.github.mikephil.charting.charts.BarChart
    android:id="@+id/spread_bar_chart"
    android:layout_width="match_parent"
    android:layout_height="300dp" />

核心代碼


public class BarChartActivity extends AppCompatActivity {
    private BarChart mBarChart;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bar_chart);
        mBarChart = findViewById(R.id.spread_bar_chart);
        
        BarData barData = getBarData(4, 100);
        showBarChart(mBarChart, barData);
    }

    private void showBarChart(BarChart chart, BarData data) {
        chart.setDrawBorders(false);
        chart.setDescription("");
        chart.setNoDataTextDescription("暫無數據");
        chart.setDrawGridBackground(false);
        chart.setGridBackgroundColor(Color.WHITE & 0x70FFFFFF);
        chart.setTouchEnabled(true);
        chart.setDragEnabled(true);
        chart.setScaleEnabled(true);
        chart.setPinchZoom(false);
        chart.setDrawBarShadow(true); // 陰影
        
        Legend legend = chart.getLegend();
        legend.setForm(Legend.LegendForm.CIRCLE);
        legend.setFormSize(6f);
        legend.setTextColor(Color.BLACK);
        
        // X軸配置
        XAxis xAxis = chart.getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setDrawGridLines(false);
        xAxis.setGranularity(1f);
        
        chart.setData(data);
        chart.animateY(2500); // Y軸動畫
        chart.invalidate();
    }

    private BarData getBarData(int count, float range) {
        List xValues = new ArrayList<>();
        for (int i = 0; i < count; i++) xValues.add("Q" + (i + 1));

        List yValues = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            float val = (float) (Math.random() * range) + 3;
            yValues.add(new BarEntry(i, val));
        }

        BarDataSet dataSet = new BarDataSet(yValues, "季度營收");
        dataSet.setColor(Color.rgb(114, 188, 223));
        dataSet.setValueTextSize(12f);
        dataSet.setValueTextColor(Color.BLACK);
        
        return new BarData(xValues, dataSet);
    }
}

進階功能與客製化

1. 數值格式化


// 保留一位小數
dataSet.setValueFormatter(new DefaultValueFormatter(1));

// 自定義格式化
dataSet.setValueFormatter(new ValueFormatter() {
    @Override
    public String getFormattedValue(float value) {
        return String.format("%,.0f", value) + "萬";
    }
});

2. 標記視圖


MarkerView mv = new CustomMarkerView(this, R.layout.custom_marker);
mv.setChartView(chart);
chart.setMarker(mv);

3. 限制縮放範圍


chart.setScaleMinima(1f, 1f); // 最小縮放
chart.setVisibleXRangeMaximum(20); // 最大可見 X 軸範圍

4. 多數據集組合圖表


LineDataSet set1 = new LineDataSet(data1, "數據集1");
LineDataSet set2 = new LineDataSet(data2, "數據集2");
LineData combinedData = new LineData(set1, set2);

5. 實時更新數據


new Thread(() -> {
    while (running) {
        runOnUiThread(() -> {
            Entry newEntry = new Entry(currentIndex++, randomValue());
            dataSet.addEntry(newEntry);
            chart.notifyDataSetChanged();
            chart.moveViewToX(currentIndex - 20); // 滾動視窗
        });
        Thread.sleep(1000);
    }
}).start();

常見問題與優化

問題解決方案
大量數據渲染卡頓啟用 setDrawValues(false)、降低幀率、使用 setViewportJob 分批渲染
X軸標籤重疊xAxis.setLabelRotationAngle(-45)、setGranularity、setLabelCount
記憶體洩漏Activity 銷毀時調用 chart.clear()、移除監聽器
動畫不流暢關閉硬體加速 chart.setLayerType(LAYER_TYPE_SOFTWARE, null)
導出圖片chart.saveToGallery("title", 50) 或 chart.getChartBitmap()

版本遷移注意 (v2 → v3)

  • 包名變更:com.github.mikephil.charting → com.github.mikephil.charting (相同)
  • Entry 建構子:new Entry(value, xIndex) → new Entry(x, y)
  • BarEntry、PieEntry 同理
  • DataSet 方法重命名:setColors → setColor (單色)、setColors(List) (多色)
  • 移除 LineData(String[] labels, List) 建構子,改用 LineData(List) + xAxis.setValueFormatter
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved