Hướng dẫn này trình bày cách vẽ một đường thẳng đơn giản lên Bitmap bằng Canvas và Paint, sau đó hiển thị lên ImageView. Đây là kỹ thuật cơ bản của custom drawing trong Android.
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: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/relativeLayout"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vẽ đường"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="70dp" />
</RelativeLayout>
Bước 3: Code MainActivity (src/MainActivity.java)
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends AppCompatActivity {
RelativeLayout relativeLayout;
Button button;
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
relativeLayout = findViewById(R.id.relativeLayout);
button = findViewById(R.id.button);
imageView = findViewById(R.id.imageView);
button.setOnClickListener(v -> {
// 1. Tạo Bitmap mutable (có thể vẽ lên)
// Width=10px là rất nhỏ - trong thực tế nên dùng kích thước View thực tế
Bitmap bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
// 2. Tạo Canvas gắn với Bitmap
Canvas canvas = new Canvas(bitmap);
// 3. Tùy chọn: fill background (mặc định trong suốt)
canvas.drawColor(Color.WHITE); // Nền trắng
// 4. Cấu hình Paint (bút vẽ)
Paint paint = new Paint();
paint.setColor(Color.RED); // Màu đường
paint.setStyle(Paint.Style.STROKE); // Chỉ vẽ viền (STROKE), không fill
paint.setStrokeWidth(8); // Độ dày 8px
paint.setAntiAlias(true); // Chống răng cưa (mượt)
// 5. Vẽ đường thẳng: drawLine(startX, startY, stopX, stopY, paint)
int offset = 50; // Lề 50px từ mép
canvas.drawLine(
offset, // startX
canvas.getHeight() / 2f, // startY (giữa chiều cao)
canvas.getWidth() - offset, // stopX
canvas.getHeight() / 2f, // stopY (giữa chiều cao)
paint
);
// 6. Hiển thị bitmap lên ImageView
imageView.setImageBitmap(bitmap);
});
}
}
Bước 4: Cấu hình 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>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Nhấn nút "Vẽ đường" - một đường ngang đỏ xuất hiện giữa ImageView.

Giải thích thành phần chính
1. Bitmap - "Cái vải" vẽ
Bitmap.createBitmap(width, height, Config.ARGB_8888): Tạo bitmap mutable (có thể chỉnh sửa)Config.ARGB_8888: 32-bit, 4 kênh (Alpha, Red, Green, Blue) - chất lượng cao- Kích thước nên dựa trên
view.getWidth(),view.getHeight()hoặcDisplayMetrics
2. Canvas - "Bàn tay" vẽ
new Canvas(bitmap): Mọi lệnh vẽ trên Canvas sẽ ghi vào Bitmap- Cung cấp các phương thức:
drawLine,drawRect,drawCircle,drawPath,drawText,drawBitmap...
3. Paint - "Bút vẽ" (Style & Color)
| Phương thức | Mô tả |
|---|---|
setColor(int) |
Màu vẽ (ARGB) |
setStyle(Style) |
FILL (tô đầy), STROKE (viền), FILL_AND_STROKE |
setStrokeWidth(float) |
Độ dày nét (pixel) |
setAntiAlias(boolean) |
Bật/tắt chống răng cưa (mượt) |
setStrokeCap(Cap) |
Đầu nét: BUTT, ROUND, SQUARE |
setStrokeJoin(Join) |
Góc nối: MITER, ROUND, BEVEL |
setPathEffect(PathEffect) |
Hiệu ứng: nét đứt (DashPathEffect), cong... |
setShader(Shader) |
Gradient, texture, bitmap pattern |
Cách đúng: Custom View (Kế thừa View)
Vẽ trong onClick của Activity không phải pattern tốt. Cách chuẩn: tạo class kế thừa View và override onDraw(Canvas).
public class LineView extends View {
private Paint paint;
public LineView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(8f);
paint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int offset = 50;
float centerY = getHeight() / 2f;
canvas.drawLine(offset, centerY, getWidth() - offset, centerY, paint);
}
}
XML: <com.example.LineView android:layout_width="match_parent" android:layout_height="200dp" />
Mở rộng: Vẽ đường nét đứt (Dashed Line)
PathEffect dashEffect = new DashPathEffect(new float[] {20, 10}, 0); // 20px vẽ, 10px bỏ
paint.setPathEffect(dashEffect);
Mở rộng: Vẽ đường cong (Path)
Path path = new Path(); path.moveTo(50, 300); path.quadTo(200, 50, 350, 300); // Đường cong bậc 2 canvas.drawPath(path, paint);
Tóm tắt
- Bitmap + Canvas + Paint = bộ ba cốt lõi custom drawing
- Luôn tạo Paint một lần (trong constructor/init), không tạo trong onDraw
- Dùng Custom View (kế thừa View) cho vẽ lặp lại/hiệu năng
- ImageView chỉ để hiển thị Bitmap tĩnh, không phải container vẽ