Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Tạo biểu đồ (Graph/Chart) trên Android với GraphView

Giới thiệu

Bài viết này hướng dẫn cách vẽ các loại biểu đồ (Line chart, Bar chart, Points) trên Android sử dụng thư viện GraphView (jjoe64). Thư viện nhẹ, dễ dùng, hỗ trợ zoom, scroll, real-time update.

Các bước thực hiện

Bước 1: Tạo dự án mới

Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.

Bước 2: Thêm dependency (build.gradle)

dependencies {
    // GraphView mới nhất
    implementation 'com.jjoe64:graphview:4.2.2'
}

Bước 3: Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <com.jjoe64.graphview.GraphView
        android:id="@+id/graph"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="16dp">

        <Button
            android:id="@+id/btnLine"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Line Chart" />

        <Button
            android:id="@+id/btnBar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginStart="8dp"
            android:text="Bar Chart" />

        <Button
            android:id="@+id/btnPoints"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginStart="8dp"
            android:text="Points" />

    </LinearLayout>

</LinearLayout>

Bước 4: Code vẽ biểu đồ (src/MainActivity.java)

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import com.jjoe64.graphview.series.BarGraphSeries;
import com.jjoe64.graphview.series.PointsGraphSeries;

public class MainActivity extends AppCompatActivity {

    private GraphView graphView;
    private Button btnLine, btnBar, btnPoints;

    // Dữ liệu mẫu
    private final DataPoint[] lineData = {
        new DataPoint(0, 1), new DataPoint(1, 5), new DataPoint(2, 3),
        new DataPoint(3, 2), new DataPoint(4, 6), new DataPoint(5, 4),
        new DataPoint(6, 7), new DataPoint(7, 5), new DataPoint(8, 8),
        new DataPoint(9, 6), new DataPoint(10, 9)
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        graphView = findViewById(R.id.graph);
        btnLine = findViewById(R.id.btnLine);
        btnBar = findViewById(R.id.btnBar);
        btnPoints = findViewById(R.id.btnPoints);

        btnLine.setOnClickListener(v -> showLineChart());
        btnBar.setOnClickListener(v -> showBarChart());
        btnPoints.setOnClickListener(v -> showPointsChart());

        // Mặc định hiển thị Line Chart
        showLineChart();
    }

    private void showLineChart() {
        graphView.removeAllSeries();
        
        LineGraphSeries series = new LineGraphSeries<>(lineData);
        series.setColor(Color.rgb(33, 150, 243)); // Material Blue
        series.setThickness(4);
        series.setDrawDataPoints(true);
        series.setDataPointsRadius(10);
        series.setDataPointsColor(Color.RED);
        series.setAnimated(true); // Animation khi vẽ
        
        // Styling viewport
        graphView.getViewport().setScalable(true);      // Zoom ngang
        graphView.getViewport().setScalableY(true);     // Zoom dọc
        graphView.getViewport().setScrollable(true);    // Cuộn ngang
        graphView.getViewport().setScrollableY(true);   // Cuộn dọc
        graphView.getViewport().setXAxisBoundsManual(true);
        graphView.getViewport().setMinX(0);
        graphView.getViewport().setMaxX(10);
        
        // Grid & Labels
        graphView.getGridLabelRenderer().setHorizontalAxisTitle("Thời gian (giờ)");
        graphView.getGridLabelRenderer().setVerticalAxisTitle("Giá trị");
        graphView.getGridLabelRenderer().setGridColor(Color.LTGRAY);
        graphView.getGridLabelRenderer().setHorizontalLabelsColor(Color.BLACK);
        graphView.getGridLabelRenderer().setVerticalLabelsColor(Color.BLACK);
        
        // Legend
        series.setTitle("Đường trend");
        graphView.getLegendRenderer().setVisible(true);
        graphView.getLegendRenderer().setAlign(LegendRenderer.LegendAlign.TOP);
        
        graphView.addSeries(series);
    }

    private void showBarChart() {
        graphView.removeAllSeries();
        
        BarGraphSeries series = new BarGraphSeries<>(lineData);
        series.setColor(Color.rgb(76, 175, 80)); // Material Green
        series.setSpacing(20); // Khoảng cách giữa các cột
        series.setDrawValuesOnTop(true);
        series.setValuesOnTopColor(Color.BLACK);
        series.setValuesOnTopSize(30);
        series.setAnimated(true);
        
        graphView.getViewport().setScalable(true);
        graphView.getViewport().setScrollable(true);
        graphView.getGridLabelRenderer().setHorizontalAxisTitle("Danh mục");
        graphView.getGridLabelRenderer().setVerticalAxisTitle("Số lượng");
        
        series.setTitle("Biểu đồ cột");
        graphView.getLegendRenderer().setVisible(true);
        
        graphView.addSeries(series);
    }

    private void showPointsChart() {
        graphView.removeAllSeries();
        
        PointsGraphSeries series = new PointsGraphSeries<>(lineData);
        series.setColor(Color.rgb(255, 152, 0)); // Material Orange
        series.setSize(16);
        series.setShape(PointsGraphSeries.Shape.POINT); // POINT, RECTANGLE, TRIANGLE
        series.setAnimated(true);
        
        graphView.getViewport().setScalable(true);
        graphView.getViewport().setScrollable(true);
        
        series.setTitle("Điểm dữ liệu");
        graphView.getLegendRenderer().setVisible(true);
        
        graphView.addSeries(series);
    }
}

Bước 5: Manifest (androidManifest.xml)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                
                
            </intent-filter>
        </activity>

    </application>
</manifest>

Chạy ứng dụng

Kết nối thiết bị, nhấn Run. Chọn các nút để chuyển đổi giữa Line, Bar, Points chart. Pinch-to-zoom, drag-to-scroll trên biểu đồ.

Các loại Series (Biểu đồ) hỗ trợ

Series Class Loại biểu đồ Đặc điểm
LineGraphSeries Đường (Line chart) Nối các điểm bằng đường, hỗ trợ đường cong (cubic)
BarGraphSeries Cột (Bar chart) Cột dọc, có thể nhóm (grouped), chồng (stacked)
PointsGraphSeries Điểm (Scatter plot) Chỉ hiển thị điểm, các hình dạng: tròn, vuông, tam giác

Tùy chỉnh nâng cao

1. Line chart cong (Smooth/Cubic)

LineGraphSeries series = new LineGraphSeries<>(data);
series.setCustomShape(new LineGraphSeries.CustomShape() {
    @Override
    public void draw(Canvas canvas, Paint paint, float x, float y, DataPoint dataPoint) {
        // Custom draw
    }
});
// Hoặc dùng cubic interpolation (cần data points đủ nhiều)
series.setDrawDataPoints(true);

2. Multiple Series (Nhiều đường trên 1 biểu đồ)

LineGraphSeries series1 = new LineGraphSeries<>(data1);
series1.setTitle("Series 1");
series1.setColor(Color.BLUE);

LineGraphSeries series2 = new LineGraphSeries<>(data2);
series2.setTitle("Series 2");
series2.setColor(Color.RED);

graphView.addSeries(series1);
graphView.addSeries(series2);
graphView.getLegendRenderer().setVisible(true);

3. Real-time / Live updating chart

// Thêm điểm mới mỗi giây
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        double x = series.getHighestValueX() + 1;
        double y = Math.random() * 10;
        series.appendData(new DataPoint(x, y), true, 50); // true = scrollToEnd, 50 = max points
        handler.postDelayed(this, 1000);
    }
}, 1000);

4. Custom Label Formatter

graphView.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter() {
    @Override
    public String formatLabel(double value, boolean isValueX) {
        if (isValueX) {
            return String.format("%.0fh", value); // "5h"
        } else {
            return String.format("$%.1f", value); // "$12.5"
        }
    }
});

Thư viện biểu đồ khác (Hiện đại hơn)

Thư viện Ưu điểm Dependency
MPAndroidChart (PhilJay) Đầy đủ tính năng nhất: combined chart, candle stick, radar, pie, animation đẹp, highlight, gesture phức tạp implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
GraphView (jjoe64) Nhẹ, đơn giản, API dễ học, đủ cho line/bar/point cơ bản implementation 'com.jjoe64:graphview:4.2.2'
HelloCharts Deprecated, không maintain Không khuyên dùng
AnyChart Commercial, đẹp, nhiều template, export image/pdf Có phí

Lưu ý

  • GraphView không còn được maintain tích cực (last update 2020). Dự án mới nên dùng MPAndroidChart.
  • Với dữ liệu lớn (>1000 points), cân nhắc downsampling hoặc dùng MPAndroidChart.
  • Luôn set setAnimated(true) cho UX mượt mà.
  • Viewport settings (scrollable, scalable) cần bật cho tương tác.