Bỏ qua để đến nội dung

Đơn vị đo (dp, sp, px)

Trong Android, có nhiều đơn vị đo khác nhau được sử dụng để định nghĩa kích thước và khoảng cách. Hiểu rõ các đơn vị này giúp bạn tạo ra giao diện hiển thị nhất quán trên nhiều thiết bị có độ phân giải và mật độ điểm ảnh khác nhau.

Mỗi màn hình có mật độ điểm ảnh (pixel density) khác nhau, do đó cùng một số lượng pixel sẽ hiển thị với kích thước vật lý khác nhau trên các thiết bị khác nhau.

Ví dụ, một View có chiều rộng 100 pixels:

  • Trên thiết bị có mật độ thấp (160 dpi): hiển thị lớn
  • Trên thiết bị có mật độ cao (480 dpi): hiển thị nhỏ hơn nhiều

dp là đơn vị được khuyến nghị sử dụng cho kích thước và khoảng cách trong layout.

  • 1 dp tương đương khoảng 1 pixel trên màn hình có mật độ trung bình (160 dpi - gọi là “baseline density”)
  • Android tự động chuyển đổi dp thành số pixel thực tế phù hợp với từng mật độ màn hình
  • Giúp giao diện hiển thị với kích thước vật lý nhất quán trên các thiết bị khác nhau

Ví dụ sử dụng dp cho margin:

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/clickme"
android:layout_marginTop="20dp" />

sp được sử dụng đặc biệt cho kích thước văn bản (text size).

  • Mặc định, sp có cùng kích thước với dp
  • Khác biệt: sp thay đổi theo cài đặt kích thước chữ mà người dùng chọn trong Settings
  • Chỉ dùng sp cho text size, không dùng cho layout

Ví dụ sử dụng sp cho text size:

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp" />

px là đơn vị pixel thực tế trên màn hình.

  • Không được khuyến nghị sử dụng trong layout
  • Kích thước hiển thị sẽ khác nhau trên các thiết bị có mật độ điểm ảnh khác nhau
  • Chỉ nên dùng khi cần thao tác với bitmap hoặc canvas ở mức pixel
  • 1 pt = 1/72 inch dựa trên kích thước vật lý của màn hình
  • Ít được sử dụng trong phát triển Android
  • Dựa trên kích thước vật lý của màn hình (tính bằng millimeter)
  • Ít được sử dụng
  • Dựa trên kích thước vật lý của màn hình (tính bằng inch)
  • Ít được sử dụng
px = dp × (dpi / 160)

Ví dụ:

  • Màn hình 160 dpi: 1 dp = 1 px
  • Màn hình 240 dpi (hdpi): 1 dp = 1.5 px
  • Màn hình 320 dpi (xhdpi): 1 dp = 2 px
  • Màn hình 480 dpi (xxhdpi): 1 dp = 3 px

Sử dụng TypedValue.applyDimension() để chuyển đổi:

Kotlin:

val dpValue = 16f
val pxValue = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dpValue,
resources.displayMetrics
).toInt()

Java:

float dpValue = 16f;
int pxValue = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dpValue,
getResources().getDisplayMetrics()
);

Android phân loại các mật độ màn hình thành các nhóm (bucket):

Qualifier Mật độ (dpi) Hệ số scale
ldpi ~120 dpi 0.75x
mdpi ~160 dpi 1.0x (baseline)
hdpi ~240 dpi 1.5x
xhdpi ~320 dpi 2.0x
xxhdpi ~480 dpi 3.0x
xxxhdpi ~640 dpi 4.0x

Cách cung cấp hình ảnh cho các mật độ khác nhau

Phần tiêu đề “Cách cung cấp hình ảnh cho các mật độ khác nhau”

Để hình ảnh hiển thị đẹp trên mọi thiết bị, bạn nên cung cấp nhiều phiên bản với kích thước khác nhau theo tỷ lệ 3:4:6:8:12:16:

res/
drawable-ldpi/ # 36×36 (0.75x)
drawable-mdpi/ # 48×48 (1.0x baseline)
drawable-hdpi/ # 72×72 (1.5x)
drawable-xhdpi/ # 96×96 (2.0x)
drawable-xxhdpi/ # 144×144 (3.0x)
drawable-xxxhdpi/ # 192×192 (4.0x)

Thay vì tạo nhiều phiên bản bitmap, bạn có thể sử dụng Vector Drawable - hình ảnh vector có thể scale mà không bị mờ:

res/
drawable/
ic_android_launcher.xml

Vector graphics đặc biệt phù hợp cho icons và các hình minh họa đơn giản.

App icons nên được đặt trong thư mục mipmap thay vì drawable:

res/
mipmap-mdpi/
ic_launcher.png
mipmap-hdpi/
ic_launcher.png
mipmap-xhdpi/
ic_launcher.png
mipmap-xxhdpi/
ic_launcher.png
mipmap-xxxhdpi/
ic_launcher.png
Đơn vị Sử dụng cho Ghi chú
dp Layout (width, height, margin, padding) ✅ Khuyến nghị
sp Text size ✅ Khuyến nghị cho text
px Thao tác low-level với bitmap ⚠️ Tránh dùng cho layout
pt, mm, in Hiếm khi sử dụng ❌ Không khuyến nghị

Trong Compose, các đơn vị này được sử dụng thông qua extension:

// dp
Box(modifier = Modifier.size(100.dp))
// sp
Text(text = "Hello", fontSize = 16.sp)