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)
LineGraphSeriesseries = 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 đồ)
LineGraphSeriesseries1 = 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.