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

Posted by

Được chỉnh sửa ngày 8/6/2017.

Chào mừng các bạn đến với bài học Android thứ 18 trong chuỗi bài học về lập trình ứng dụng Android 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.

Style
Theme
String
– Và Color

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.

Screen Shot 2017-05-17 at 15.59.43

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.

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é.

dimen_1

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 ưng ý với các tỉ lệ thành phần trên màn hình luôn nhất quán. 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.

Truy Xuất Đến Dimen

Chúng ta cùng nhau điểm qua hai cách truy xuất đến dimen, đó là, truy xuất từ XML và từ Java code.

Truy Xuất Từ File XML

Từ bất kỳ file XML nào, nếu bạn muốn dùng đến resource dimen này, thì hãy gọi đến chúng thông qua @dimen/tên_dimen. Như bạn có thể thấy với activity_main.xml của TourNote.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.yellowcode.tournote.MainActivity">

    <TextView
        android:id="@+id/activity_main_tv_empty"
        style="@style/InformationTextView"
        android:layout_centerInParent="true"
        android:text="@string/mainscreen_empty_note" />

    <ImageView
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_below="@id/activity_main_tv_empty"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="8dp"
        android:scaleType="fitCenter"
        android:src="@drawable/empty_note" />

</RelativeLayout>

Truy Xuất Từ Java Code

Việc bạn dùng đến dimen từ Java code là hiếm hơn so với XML. Đó là bởi nó liên quan đến việc tương đồng về đơn vị. Cụ thể hơn, với các hàm Java liên quan đến kích thước, đa phần chúng chấp nhận tham số truyền vào là pixel, nhưng khi khai báo một dimen trong XML resource, bạn được khuyên không nên dùng đến pixel. Do đó khi sử dụng dimen ở Java code, bạn phải chú ý xây dựng thêm các hàm chuyển đổi từ đơn vị khác sang pixel. Tuy nhiên vì mục đích nào đó bạn muốn truy xuất đế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.

// Mình có đặt id cho cho ImageView này ở XML là activity_main_imv_empty
ImageView imageView = (ImageView) findViewById(R.id.activity_main_imv_empty);

// 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.

Screenshot_1495076237

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.

Tất nhiên 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 run 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. 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é.

pixel_1

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 điểm ảnh.

– 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 điểm ảnh, 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.

pixel_2

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.

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, Google 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 đó Google đư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. 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. Bạn chú ý là mình có định nghĩa vài dimen thừa để mà dùng cho tương lai nữa nhé.

<resources>

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

    <!-- Padding -->
    <dimen name="padding_tiny">2dp</dimen>
    <dimen name="padding_small">4dp</dimen>
    <dimen name="padding_medium">8dp</dimen>
    <dimen name="padding_large">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.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.yellowcode.tournote.MainActivity">

    <TextView
        android:id="@+id/activity_main_tv_empty"
        style="@style/InformationTextView"
        android:layout_centerInParent="true"
        android:text="@string/mainscreen_empty_note" />

    <ImageView
        android:layout_width="@dimen/empty_icon_width"
        android:layout_height="@dimen/empty_icon_height"
        android:layout_below="@id/activity_main_tv_empty"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/padding_medium"
        android:scaleType="fitCenter"
        android:src="@drawable/empty_note" />

</RelativeLayout>

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 đánh giá 5 sao nếu thấy thích bài viết, hãy comment bên dưới nếu có thắc mắc, hãy để lại địa chỉ email của bạn để nhận được thông báo mới nhất khi có bài viết mới, và nhớ chia sẻ các bài viết của Yellow Code Books đến nhiều người khác nữa nhé.

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.

Advertisements
Rating: 5.0/5. From 10 votes.
Please wait...

2 comments

Gửi phản hồi