Thiết kế cho các thiết bị khác nhau

Giao diện người dùng (user interfaces – UI) của các ứng dụng Android phải được thiết kế sao cho tương thích với với các thiết bị di động như điện thoại thông minh hay máy tính bảng có kích thước khác nhau. Ngoài ra, mỗi thiết bị lại có hai chế độ xem là portrait (hướng dọc) và landscape (hướng ngang) nên giao diện ứng dụng cũng cần thay đổi một cách tương ứng với mỗi chế độ.

Views và views group

Một giao diện người dùng của ứng dụng Android được tạo thành bởi nhiều phần tử khác nhau. Mỗi phần tử trên giao diện là một lớp con của lớp View (android.view.View). Các views trong Android còn được gọi là các widgets hay components. Android SDK cung cấp nhiều views được xây dựng sẵn hỗ trợ cho việc thiết kế giao diện như Button, CheckBox, TextView, v.v.

Mỗi view có thể chứa nhiều views khác, lúc này chúng ta gọi là view group. Mỗi view group là lớp con của lớp ViewGroup (android.view.ViewGroup) và ViewGroup lại là lớp con của lớp View. Một ví dụ về ViewGroup có sẵn là RadioGroup chứa các RadioButton.

Một dạng khác của ViewGroup là layout manager (trình quản lý layout).

Layout managers

Một layout là một dạng của ViewGroup nên cũng là lớp con của lớp ViewGroup. Nhiệm vụ của layout là kiểm soát cách thức các thành phần hay views được định vị trong giao diện màn hình.

Android SDK cung cấp một số layouts hỗ trợ cho việc thiết kế giao diện gồm:

  • ConstraintLayout (hỗ trợ từ Android Studio 3.0 hay Android 8)
  • LinearLayout
  • TableLayout
  • FrameLayout
  • GridLayout
  • RelativeLayout
  • AssoluteLayout
  • CoordinatorLayout

Một số layout không được khuyên dùng như AbsoluteLayout vì tính “cứng nhắc” của nó hay một số layout đã lỗi thời như CoordinatorLayout. Các layout sẽ được đề cập kĩ hơn trong các bài viết sau này.

Thiết kế giao diện người dùng

Chúng ta có thể thiết kế giao diện cho ứng dụng trong môi trường Android Studio 3.X theo 3 cách (còn một cách khác là kết hợp các cách này):

  • Dùng các view được xây dựng sẵn: có thể dùng các views từ thanh công cụ Palette
  • Dùng ngôn ngữ XML
  • Dùng java

Thông thường chúng ta dùng các views từ thanh Palette và thỉnh thoảng thiết kế hay điều chỉnh lại giao diện bằng ngôn ngữ XML, và một số ít trường hợp dùng Java. Trong các ứng dụng Android phức tạp, thiết kế giao diện là sự kết hợp linh động giữa các cách trên.

Hệ thống các views

Các views trên một giao diện người dùng được tổ chức theo một hệ thống thứ bậc các views (giống như một hệ thống thư mục). Các views trên một giao diện được chứa trong một view duy nhất gọi là view gốc (giống như thư mục gốc). Việc tổ chức hệ thống các views như thế nào tùy thuộc vào giao diện của mỗi ứng dụng, quan điểm của người thiết kế và cả người dùng. Ví dụ giao diện một ứng dụng đơn giản như sau:

Giao diện trên gồm hai Button và bốn CheckBox. Cấu trúc các views cho giao diện này có thể như sau:

View gốc là một RelativeLayout chứa hai layout khác là LinearLayout (chứa hai Button) và TableLayout (chứa bốn CheckBox). Chúng ta cũng có thể thể hiện cấu trúc trên theo dạng cây như sau:

Tạo dự án mới

Trong các bài trước, chúng ta đã từng tạo một ứng dụng Android với giao diện đơn giản và làm quen với công cụ thiết kế giao diện trong môi trường Android Studio 3.X. Trong bài này chúng ta sẽ tìm hiểu kỹ hơn về công cụ thiết kế Android Studio.

Đầu tiên, chúng ta sẽ tạo một dự án mới với tên là LayoutSample với các thông tin như hình sau:

Nhấn Next. Chọn API 14 từ mục Phone and Tablet và nhấn Next. Trong phần Add an Activity to Mobile, chúng ta sẽ không chọn Activity nào bằng cách chọn Add No Activity:

Nhấn Finish.

Tạo một Activity

Do ở trên chúng ta đã không chọn một Activity nào từ danh sách các mẫu Activity nên chúng ta phải tự tạo một Activity mới. Giao diện ứng dụng LayoutSample lúc này:

Mở cửa sổ Project bằng tổ hợp phím Alt + 1 hay chọn View > Tool Windows > Project

Chọn thư mục app > java > com.ngocminhtran.layoutsample và nhấp chuột phải thư mục này chọn New > Activity > Empty Activity:

Trong hộp thoại New Android Activity nhập tên Activity tại Activity NameLayoutSampleActivityLayout Name tương ứng là activity_layout_sample. Chúng ta cũng cần chọn checkbox Generate Layout File để phát sinh tập tin tài nguyên của layout. Tùy chọn Launcher Activity cho phép chúng ta chọn Activity nào sẽ xuất hiện đầu tiên khi một ứng dụng có nhiều Activity. Vì ứng dụng của chúng ta chỉ có một Activity nên khi ứng dụng được tải xuống thiết bị chúng ta muốn Activity hiện tại xuất hiện nên checkbox Launcher Activity phải được chọn

Nhấn Finish.

Lúc này, Android Studio sẽ thêm một số tập tin đến dự án. Một tập tin java (LayoutSampleActivity.java) sẽ được thêm đến thư mục app > java > com.ngocminhtran.layoutsample:

Một tập tin XML (activity_layout_sample.xml) phát sinh layout ứng dụng trong thư mục app > res > layout:

Và một tập tin XML khác chứa các thông tin về Activity là AndroidManifest.xml cũng được thêm đến thư mục app > manifests:

Nội dung của tập tin này như sau:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ngocminhtran.layoutsample">

    <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=".LayoutSampleActivity">
          <intent-filter>
             <action android:name="android.intent.action.MAIN" />
             <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
       </activity>
    </application>
</manifest>

Không gian thiết kế giao diện Android Studio

Mở tập tin activity_layout_sample.xml bằng cách tìm đến thư mục app > res > layout và nhấp đôi chuột vào tập tin activity_layout_sample.xml. Mặc định, các thành phần (views) trong giao diện ứng dụng của chúng ta sẽ được tổ chức trong một ConstraintLayout. Có thể dễ dàng thấy điều này bằng cách chọn chế độ Text để xem mã XML của tập tin activity_layout_sample.xml:

Mã XML như sau:


<?xml version="1.0" encoding="utf-8"?>
<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=".LayoutSampleActivity">

</android.support.constraint.ConstraintLayout>

Chúng ta có thể thêm bất cứ thành phần nào như Button, TextView, v.v. đến giao diện vào giữa cặp <android.support.constraint.ConstraintLayout> và </android.support.constraint.ConstraintLayout>. Tuy nhiên, để đơn giản hơn, chúng ta sẽ thiết kế giao diện ứng dụng trong chế độ Design:

Mặc định, trong chế độ Design chúng ta sẽ có hai khung nhìn là Design – cho phép chúng ta xem trước giao diện trên các thiết bị thực – và Blueprint – chỉ là phác thảo giao diện:

Chúng ta có thể xem thông tin hay thay đổi không gian thiết kế nhờ thanh công cụ phía trên hai khung nhìn:

Có thể chỉ chọn khung nhìn Design hay chỉ chọn khung nhìn Blueprint hay chọn cả hai cùng lúc (mặc định) bằng cách vào mục Select Design Surface (B) trên thanh công cụ:

Có thể thay đổi hướng khung nhìn như Potrait (mặc định) hay Landscape và một số tùy chọn khác bằng cách vào mục Orientation in Editor (O) trên thanh công cụ:

Chúng ta cũng có thể xem hay điều chỉnh thông tin về thiết bị (trong trường hợp của chúng ta là Nexus 4), về phiên bản API (trong trường hợp của chúng ta là API 27), theme (trong trường hợp của chúng ta là AppTheme), phóng to hay thu nhỏ khung nhìn, v.v.

Bên cạnh các khung nhìn như Design hay Blueprint, thanh công cụ, không gian thiết kế trong Android Studio còn cung cấp thanh Palette chứa các thành phần cơ bản trong một giao diện như Button, TextView, v.v. và khung Component Tree giúp chúng ta kiểm soát cấu trúc của giao diện đang thiết kế:

Chúng ta có thể ẩn hai khung PaletteComponent Tree bằng cách nhấn vào nút mũi tên bên góc phải trên của mỗi khung:

Để hiện một trong hai công cụ này chỉ cần nhấn chuột trái vào tên công cụ tương ứng.

Một cửa sổ thông tin quan trọng khác mà chúng ta không thể bỏ qua trong không gian thiết kế là cửa sổ Attributes bên phải màn hình:

Cửa sổ Attributes cung cấp các thông tin hay thuộc tính của các thành phần trên giao diện ứng dụng. Hiện tại trên hình của chúng ta cửa sổ Attributes trống vì chúng ta chưa chọn một thành phần nào trên khung nhìn Design. Thử nhấp chuột trái vào khung nhìn Design và kết quả:

Mỗi thành phần trong UI sẽ có nhiều thuộc tính khác nhau và chúng ta sẽ tìm hiểu về chúng trong phần sau của bài viết này hay các bài viết kế tiếp.

Thiết kế giao diện

Android Studio hỗ trợ chúng ta thiết kế giao diện bằng nhiều cách như dùng mã Java, viết mã XML hay dùng các công cụ trực quan. Trong phần này chúng ta sẽ tìm hiểu cách thiết kế bằng công cụ trực quan và bằng mã XML; tạo giao diện bằng mã Java sẽ được tìm hiểu trong các bài sau.

Dùng công cụ trực quan

Trở lại tập tin activity_layout_sample.xml trong chế độ Design. Trong bài Dạo quanh ứng dụng Android trong Android Studio 3.X  chúng ta đã tìm hiểu qua cách thiết kế một giao diện người dùng đơn giản dùng các thành phần từ thanh Palette, cách định vị và khắc phụ các lỗi hay cảnh báo khi thêm một thành phần như Button hay TextView đến khung nhìn Design. Trong phần này sẽ không đề cập lại các khía cạnh trên. Bạn có thể xem lại bài viết này.

Thêm một Button từ mục Common trên thanh Palette đến khung nhìn Design. Định vị lại Button trên khung nhìn:

Mở tập tin strings.xml trong thư mục app > res > values và thêm dòng mã XML sau:


<resources>
   <string name="app_name">LayoutSample</string>
   <string name="button_string">Press Me</string>
</resources>

Đóng tập tin strings.xml và trở lại tập tin activity_layout_sample.xml trong chế độ Design. Chọn Button và thay đổi thông tin các thuộc tính  IDtext (mục TextView) của Button này trong khung Attributes tương ứng là btnPress@string/button_string:

Bây giờ, thêm một PlainText trong mục Text từ thanh Palette. Định vị nó phía trên Button:

Mở tập tin strings.xml trong thư mục app > res > values và thêm dòng mã XML sau:


<resources>
    <string name="app_name">LayoutSample</string>
    <string name="button_string">Press Me</string>
    <string name="message_string">Enter a message</string>
</resources>

Đóng tập tin strings.xml và trở lại tập tin activity_layout_sample.xml trong chế độ Design. Chọn PlainText và thay đổi thông tin các thuộc tính  IDtext (mục TextView) của PlainText này trong khung Attributes tương ứng là message@string/message_string, tìm đến thuộc tính Width (nếu không tìm thấy thì có thể mở rộng khung Attributes bằng cách nhấn chuột vào liên kết View all attributes) và nhập vào giá trị là 350dp. Giao diện lúc này:

Một số đơn vị đo lường được hỗ trợ:

  • dp (Density independent pixels): Một đơn vị đo lường trừu tượng dựa trên mật độ vật lý của màn hình thiết bị. 1dp = 1/160 inches.
  • in: đơn vị inches
  • pt: points. 1pt = 1/72 inches
  • mm: milimet
  • sp (Scale independent pixels): tương tự dp nhưng sp dựa trên font chữ
  • px: pixels

Trong các đơn vị trên thì dp được khuyên dùng vì nó mang lại sự sắc nét nhất cho giao diện.

Dùng mã XML

Chúng ta có thể thiết kế giao diện với mã XML bằng cách chuyển tập tin activity_layout_sample.xml sang chế độ Text. Thực tế, hai chế độ TextDesign có quan hệ chặt chẽ với nhau. Nếu các thành phần được thêm vào giao diện trong chế độ Design thì mã XML sẽ tự động phát sinh trong chế độ Text và ngược lại. Mã XML của tập tin activity_layout_sample.xml lúc này:


<?xml version="1.0" encoding="utf-8"?>
<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=".LayoutSampleActivity">

   <Button
       android:id="@+id/btnPress"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_marginBottom="8dp"
       android:layout_marginEnd="8dp"
       android:layout_marginLeft="8dp"
       android:layout_marginRight="8dp"
       android:layout_marginStart="8dp"
       android:layout_marginTop="128dp"
       android:text="@string/button_string"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintHorizontal_bias="0.532"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent"
       app:layout_constraintVertical_bias="0.422" />

   <EditText
       android:id="@+id/message"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_marginBottom="2dp"
       android:layout_marginEnd="8dp"
       android:layout_marginLeft="8dp"
       android:layout_marginRight="8dp"
       android:layout_marginStart="8dp"
       android:layout_marginTop="8dp"
       android:width="350dp"
       android:ems="10"
       android:inputType="textPersonName"
       android:text="@string/message_string"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintHorizontal_bias="0.503"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent"
       app:layout_constraintVertical_bias="0.447" />
</android.support.constraint.ConstraintLayout>

Đoạn mã XML được tổ chức theo cấu trúc dạng cây, bắt đầu bằng khai báo phiên bảng XML và chế độ mã hóa:


<?xml version="1.0" encoding="utf-8"?>

Kế tiếp là phần tử gốc của giao diện ConstraintLayout. ConstraintLayout được tạo ra bằng thẻ mở <ConstraintLayout> và thẻ đóng </ConstraintLayout>. Các thuộc tính của ConstraintLayout như xmlns:android, xmlns:app, v.v. được thêm trong thẻ mở <ConstraintLayout >

ConstraintLayout chứa hai phần tử con là ButtonEditText. Đây là các phần tử tự đóng – tức là không phân biệt thẻ đóng và thẻ mở mà mỗi phần tử sẽ bắt đầu bằng dấu “<” và kết thúc bằng “/>”, cụ thể là, <Button…/> và <EditText…/>. Mỗi phần tử như Button hay EditText chứa nhiều thuộc tính như id, text, width,…

Việc thiết kế giao diện dùng mã XML đòi hỏi chúng ta phải nhớ rất nhiều tên thành phần và các thuộc tính tương ứng. Bên cạnh đó cú pháp cũng cần phải chú ý. Do đó, thiết kế giao diện dùng công cụ trực quan hay chế độ Design thường được ưu tiên và chỉ dùng đến mã XML trong trường hợp cần một vài can thiệp nhỏ đến giao diện.

Layout Inspector

Android Studio 3.X cung cấp một cung cụ tiện ích là Layout Inspector giúp chúng ta kiểm soát, so sánh các layouts tốt hơn. Để dùng Layout Inspector chúng ta cần:

  • Mở ứng dụng từ máy ảo Android hay Genymotion
  • Vào Tools > Layout Inspector
  • Chọn ứng dụng từ hộp thoại Choose Process

Khung ViewTree sẽ xuất hiện cho phép chúng ta xem các thành phần giao diện trong khi ứng dụng đang chạy

Có thể tìm hiểu thêm về công cụ hữu ích này tại Android Developer.

Tổng kết

Trong bài này chúng ta đã tìm hiểu về hai cách thức quan trọng trong thiết kế giao diện người dùng ứng dụng Android là dùng công cụ trực quan (kéo-thả) và dùng mã XML. Chúng ta cũng đã tìm hiểu sơ lược về công cụ Layout Inspector. Trong bài kế tiếp chúng ta sẽ tìm hiểu cách thiết kế giao diện bằng mã Java.