Android Bài 18: Sử Dụng Dimen

Posted by
Rating: 5.0/5. From 18 votes.
Please wait...

Được chỉnh sửa ngày 12/07/2019.

Chào mừng các bạn đã đến với bài học Android thứ 18, bài học về cách sử dụng Dimen. Đây là bài học trong chuỗi bài viết về lập trình ứng dụng Android bằng Java của Yellow Code Books.

Hôm nay chúng ta tiếp tục nói về cách sử dụng một loại resource nữa của Android. Resource có cái tên hơi lạ – Dimen. Muốn biết nó thực chất là loại resource gì thì mời bạn cùng đọc qua bài viết hôm nay. Tuy nhiên mình xin tổng hợp lại, cho đến giờ phút này chúng ta đã nói qua cách sử dụng các resource sau đây.

Mình bật mí một chút về resource dimen này. Resource này liên quan đến các “số đo” bên trong ứng dụng, hay còn gọi là kích thước. Tuy dễ nhưng quan trọng, vì chúng có liên quan đến việc tạo ra một giao diện “động” (về kích thước) cho vô vàn các màn hình đang có mặt ngoài thị trường ngày nay.

Giới Thiệu Dimen Resource

Chúng ta cùng làm quen đến nơi “cất giấu” và cách khai báo loại resource này trước. Còn cách sử dụng cho từng dimen sẽ được mình giải thích cụ thể ở các phần sau của bài học.

Dimen, viết tắt của chữ Dimension, dịch ra là Kích thước. Vâng, resource này giúp bạn định nghĩa tất cả các kích thước của các view hoặc các thành phần khác trong ứng dụng, bao gồm cả font size, vào cùng một file resource để dễ quản lý. Đầu tiên bạn nên biết, đó là resource này được để trong thư mục res/values/ (hoặc res/values-xxx/ nếu dùng theo kiểu alternative resource), cùng thư mục với style, theme, string, và color. File chứa đựng các dimen này chính là file dimens.xml.

Nơi chứa đựng file resource dimen
Nơi chứa đựng file resource dimen

Khi bạn tạo mới project, thì hệ thống cũng đã để mặc định một vài thông số dimen trong file này rồi, bạn thử click đúp để mở file lên xem. Như bạn cũng biết, bất cứ file XML nào bên trong thư mục values/ cũng đều có thẻ gốc là resources. Bên trong thẻ resources này là các thẻ con dimen.

Cấu trúc file dimen
Cấu trúc file dimen

Sử Dụng Dimen Resource

Dimen cũng giống color, chỉ có một cách dùng cho từng trường hợp XML hay Java code. Tuy nhiên bạn nên chú ý một chút đến đơn vị đo lường, mình sẽ nói rõ từng đơn vị mà Android hỗ trợ, bên dưới mục khai báo dưới đây.

Khai Báo Dimen

Mỗi loại kích thước được khai báo trong một thẻ dimen (1), và được đặt một cái tên theo sau thuộc tính name (2). Độ lớn của kích thước được chỉ định ở (3), kích thước này có thể là số nguyên, cũng có thể là số thực. Nhưng bạn phải luôn nhớ đơn vị kèm theo kích thước, như trong hình bạn thấy đơn vị của các dimen đều là dp, bạn chỉ định đơn vị nào trong các đơn vị mà mình liệt kê dưới đây cũng được, tuy nhiên nếu không có chỉ định đơn vị cho dimen thì khi build, hệ thống sẽ báo lỗi đấy nhé.

Cấu trúc một thẻ dimen
Cấu trúc một thẻ dimen

Các Đơn Vị Mà Android Hỗ Trợ

Bạn vừa làm quen với việc khai báo một dimen, vậy thì các đơn vị mà Android hỗ trợ là những đơn vị nào.

  • dpDensity-independent Pixel – Mình đề nghị các bạn nên dùng đơn vị này cho tất cả các kích thước bên trong ứng dụng, kể cả cho padding và margin. Lý do cụ thể vì sao thì mình sẽ giải thích ở mục tiếp theo bên dưới bài học hôm nay.
  • spScale-independent Pixel –  Thông số này tương tự như dp, nhưng dùng khi định nghĩa font size. Cụ thể của sp sẽ được mình nói rõ ở bài học về sử dụng font.
  • ptPoint – Một point được tính bằng 1/72 inch dựa trên loại màn hình 72 dpi. Mình chưa từng sử dụng đơn vị point này, chắc là nó sẽ giúp ích cho một số ứng dụng có làm việc với máy in, để đảm bảo kích thước thật trong qua trình thiết kế.
  • pxPixel – Dựa trên đơn vị pixel vật lý của thiết bị. Như mình có nói rõ ở mục dưới đây, pixel không giúp bạn tạo được một giao diện nhất quán cho các tỉ lệ màn hình khác nhau ngoài thị trường. Do đó tốt nhất bạn nên chọn dp hoặc sp để thay thế.
  • mmMilimet – Dựa trên đơn vị milimet thực tế. Mình cũng chưa từng sử dụng đơn vị này, có lẽ ứng dụng của nó cũng giống như với đơn vị pt.
  • inInch – Dựa trên đơn vị inch thực tế. Và mình cũng chưa từng sử dụng nốt.

Sử Dụng Dimen

Chúng ta cùng nhau điểm qua hai cách sử dụng đến dimen đã khai báo trên kia. Đó là, sử dụng ở XML và ở Java code.

Sử Dụng Ở File XML

Từ bất kỳ file XML nào, nếu bạn muốn dùng đến resource dimen này, nếu bạn đang ở tab Design, thì ở các field liên quan đến kích thước, bạn có thể nhấn vào nơi được khoanh tròn trong hình dưới để mở ra một cửa sổ liệt kê tất cả các dimen, bạn chỉ việc chọn lựa dimen đã khai báo sẵn mà thôi.

Nhấn vào những nơi như chỗ khoanh tròn, sẽ hiện ra cửa sổ với các dimen có sẵn
Nhấn vào những nơi như chỗ khoanh tròn, sẽ hiện ra cửa sổ với các dimen có sẵn

Còn nếu bạn đang ở tab Text, thì hãy dùng đến các dimen thông qua cú pháp @dimen/tên_dimen. Một lát nữa đến bài thực hành bạn sẽ hiểu rõ hơn cách sử dụng này.

Dử Dụng Ở Java Code

Nếu bạn muốn sử dụng đến các dimen đã khai báo ở Java code, thì hãy truyền R.dimen.tên_dimen vào hàm cần thiết.

Như ví dụ sau, mình sẽ thử set lại chiều dài và rộng của ảnh empty_note bằng giá trị mới activity_horizontal_margin đã khai báo trong dimen. Như vậy trong XML khai đã báo kích thước này là 60dp, nhưng khi ứng dụng thực thi, Java code set lại giá trị này thành 16dp.

public class MainActivity extends AppCompatActivity {

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

        // R.id.imageView chính là id của ImageView bên file XML
        ImageView imageView = (ImageView) findViewById(R.id.imageView);

        // Set lại kích cỡ cho imageView
        imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin);
        imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin);
    }
}

Và kết quả thực thi lại chương trình.

Thực thi thử các dòng code sử dụng dimen ở Java code
Thực thi thử các dòng code sử dụng dimen ở Java code

Dùng pixel Hay dp?

Như trên đây, mình có nói qua rằng bạn đừng nên sử dụng đơn vị pixel để chỉ định các kích thước trong giao diện, mà hãy sử dụng dp hay sp. Kiến thức của phần này chẳng ở đâu xa, bạn vào trang developer của Android này sẽ có đầy đủ, mình chỉ tổng hợp lại vài ý quan trọng.

Thử Biểu Diễn Ảnh Bằng pixel

Mình tin chắc rằng hầu hết các bạn đều biết đến khái niệm pixel, đó là một điểm ảnh, một đơn vị ảnh vật lý được phát sáng bằng sự tập hợp của ba màu đặc trưng R-G-B mà mình có nhắc đến ở bài hôm trước.

Không thể phủ nhận rằng pixel là một đơn vị đo lường hữu dụng, không những trong thiết kế, mà với một số ngôn ngữ lập trình, tiêu chí sử dụng pixel để hiện thực giao diện cũng khá phổ biến. Thế nhưng, tại vì sao mà Android không khuyến khích bạn dùng pixel nữa? Chúng ta cùng xem ví dụ sau, ví dụ này mình hiển thị một ảnh có kích thước 160×160 pixel, nhưng khi thực thi ví dụ này lên ba thể loại màn hình sau, kích cỡ và tỉ lệ của chúng không đồng nhất.

Cùng một kích cỡ pixel, nhưng khi hiển thị ở 3 màn hình khác nhau sẽ cảm giác như chúng khác kích cỡ nhau
Cùng một kích cỡ pixel, nhưng khi hiển thị ở 3 màn hình khác nhau sẽ cảm giác như chúng khác kích cỡ nhau

Với cái cách mà một ảnh hiển thị trông khác nhau về tỉ lệ giữa các màn hình như thế này, sẽ làm bạn vô cùng khó khăn trong việc thiết kế các giao diện phức tạp khác đấy nhé.

Vậy chúng ta cùng xem qua tại sao có sự khác nhau về tỉ lệ của ảnh có cùng một kích cỡ như trên. Bạn biết không, ba màn hình mình cố tình dùng đến có “mật độ điểm ảnh” khác nhau, mật độ điểm ảnh này chính là số lượng pixel trên một inch màn hình, người ta gọi thông số này là PPI (Pixels Per Inch).

  • Với hình đầu tiên, màn hình Medium density này có 240 ppi. Như vậy một inch của nó chứa 240 pixel.
  • Màn hình thứ hai, High density, có 320 ppi. Một inch trên màn hình này chứa 320 pixel, vậy là nếu như hai loại màn hình đầu tiên này có thông số inch giống nhau, ví dụ 5.5 inch, thì màn hình High density sẽ có độ phân giải cao hơn và cho chất lượng ảnh “mịn” hơn Medium density.
  • Tương tự, Extra high density có 480 ppi. Nên sẽ có độ phân giải và khả năng hiển thị ảnh mịn hơn hai loại trên kia nếu cùng thông số inch.

Dựa vào số lượng pixel trên một inch, mời bạn tiếp tục nhìn lại cả ba màn hình, với ô vuông màu đỏ của mình biểu thị cho một inch. Medium density có 240 pixel trong một inch, nên ảnh 160 pixel sẽ như chiếm 2/3 inch. High density có 320 pixel trong một inch, do đó ảnh 160 pixel sẽ chiếm 1/2 inch. Cuối cùng, Extra high density có 480 pixel trong một inch, thì ảnh 160 pixel sẽ chiếm 1/3 inch.

Ô vuông đỏ chính là 1 inch vật lý
Ô vuông đỏ chính là 1 inch vật lý

Chuyển Sang Biểu Diễn Ảnh Bằng dp

Như vậy bạn đã biết rằng dùng pixel trong Android “thất bại” như thế nào thông qua ví dụ trên. Chúng ta hãy xem việc chuyển ảnh trên từ 160×160 pixel sang 160×160 dp xem như thế nào nhé. Kết quả như sau.

Biểu diễn lại kích cỡ của ảnh bằng dp
Biểu diễn lại kích cỡ của ảnh bằng dp

Bạn có thể thấy rằng, có thể tỉ lệ giữa ảnh và các khoảng trống còn lại ở từng màn hình vẫn chưa hoàn hảo, nhưng biểu diễn theo dp như thế này tốt hơn nhiều so với pixel rồi đúng không nào. Tại sao lại như vậy, chúng ta cùng xem cách mà Android hoạt động với dp nhé.

Đầu tiên, Android lấy một loại màn hình làm chuẩn, đó là màn hình 160 dpi. Với thể loại màn hình này thì 1 pixel tương đương với 1 dp. Vậy với các màn hình còn lại? Khi đó Android đưa ra công thức.

px = dp * (dpi / 160)

Nếu chúng ta bỏ qua sự khác biệt giữa ppidpi. Thì với màn hình Medium density ở ví dụ trên có 240 ppi, chúng ta khai báo ảnh 160 dp, vậy hệ thống sẽ áp dụng công thức và sẽ vẽ ảnh với 160 * (240 / 160) = 240 pixel. Tương tự như vậy với High density có 320 ppi, hệ thống sẽ vẽ ảnh 320×320 pixel. Và với Extra high density thì ảnh này được vẽ với kích thước 480×480 pixel. Sự linh động về pixel như vậy giúp giao diện chúng ta có được các tỉ lệ tương đương cho tất cả các màn hình ngoài thị trường. Giờ thì bạn đã hiểu rồi đúng không nào.

Thực Hành Truy Xuất Đến File Dimen

Và cuối cùng, chúng ta cũng nên vọc vọc cho TourNote một tí cho nhớ bài. Nếu bạn có thử code gì cho MainActivity.java như ví dụ thay đổi kích thước ảnh trên đây thì xóa đi nhé.

Mình nhắc lại tí, là bạn đã từng mang resource string về để trong strings.xml, mang resource color về colors.xml. Vậy thì resource dimen cũng phải được mang về dimens.xml. Việc file activity_main.xml có định nghĩa cứng kích thước và các margin ở nội dung của nó là không được, sau này khi cần chỉnh sửa chúng ta sẽ rất mệt mỏi khi phải tìm vào từng layout.

Vậy các bạn hãy mở file dimens.xml lên và thêm vào vài thông tin sau.

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>

    <!-- Main Activity components -->
    <dimen name="empty_icon_width">60dp</dimen>
    <dimen name="empty_icon_height">60dp</dimen>
</resources>

Bây giờ bạn hãy vào lại activity_main.xml để điều chỉnh các thông số cho ImageView như sau. Bạn hãy đảm bảo đang ở tab Design. Hãy nhấn chọn vào ImageView ở giữa màn hình. Ở cửa sổ Attributes bên phải, tìm đến các field layout_widthlayout_height. Bạn lần lượt nhấn vào nơi để thay đổi kích thước này như hình ảnh ở mục trên kia mình có nói đến.

Vùng khoanh đỏ cho bạn tùy chọn đến các dimen đã định nghĩa sẵn
Vùng khoanh đỏ cho bạn tùy chọn đến các dimen đã định nghĩa sẵn

Poup sau xuất hiện sẽ liệt kê các dimen có thể có, kể cả 2 dimen mà bạn vừa khai báo xong trên kia luôn nhé, hãy lần lượt chọn empty_icon_width cho layout_width, và chọn empty_icon_height cho layout_height của ImageView.

Cửa sổ này liệt kê các dimen mà bạn cần
Cửa sổ này liệt kê các dimen mà bạn cần

Sau đây là kết quả ở cửa số Attribute mà bạn đã thiết lập.

Kết quả sau khi set dimen cho ImageView
Kết quả sau khi set dimen cho ImageView

Bạn có thể chuyển qua tab Text để xem code XML thay đổi như thế nào nhé.

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/activity_main_tv_empty"
        style="@style/InformationTextView"
        android:text="@string/mainscreen_empty_note"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="@dimen/empty_icon_width"
        android:layout_height="@dimen/empty_icon_height"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:scaleType="fitCenter"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/activity_main_tv_empty"
        app:srcCompat="@drawable/empty_note" />

</android.support.constraint.ConstraintLayout>

Xong. Bạn có thể chạy lại ứng dụng để kiểm chứng. Tuy nhiên mọi thứ ở bài thực hành hôm nay sẽ không làm cho TourNote khác đi chút giao diện nào. Chỉ là giúp cho code được chuyên nghiệp hơn thôi.

Download Source Code Mẫu

Bạn có thể download source code mẫu của bài này ở đây.

Như vậy với bài học về resource dimen hôm nay, thì chúng ta đã kết thúc các thể loại resource “chính thống” có trong thư mục res/values/. Cũng còn vài loại resource nữa bên trong thư mục values/ này, tuy nhiên nó không quan trọng lắm, mình đang cân nhắc sẽ nói đến tất cả các resource còn lại có thể có bên trong thư mục này ở bài tiếp theo, hoặc sẽ nói đến thể loại resource khác không thuộc quản lý của thư mục values/, đó là resource drawable. Bạn chờ xem nhé.

Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy ủng hộ blog bằng cách:

Đánh giá 5 sao bên dưới mỗi bài nếu thấy thích.
Comment bên dưới mỗi bài nếu có thắc mắc.
Để lại địa chỉ email của bạn ở thanh bên phải để nhận được thông báo sớm nhất khi có bài viết mới.
Chia sẻ các bài viết của Yellow Code Books đến nhiều người khác.

Bài Kế Tiếp

Bạn sẽ làm quen với các resource còn lại bên trong thư mục res/values/ trước khi chính thức đi qua một dạng resource mới mẻ khác.

3 comments

  1. Reblogged this on gioilaptrinh.

    No votes yet.
    Please wait...
  2. Thanks tác giả nhiều, bài viết rất cặn kẽ, rõ ràng. Pác thật là có tâm

    No votes yet.
    Please wait...
  3. Cảm ơn bạn , bài viết rất hay !

    Rating: 5.0/5. From 1 vote.
    Please wait...

Gửi phản hồi