Giao diện người dùng của một ứng dụng Android được xây dựng bằng các đối tượng View
và ViewGroup. View
là các đối tượng như button (nút bấm), text field (ô gõ văn bản)… ViewGroup
là các khung dùng để chứa các đối tượng View
khác, ViewGroup
quy định kích thước cũng như vị trí của các View
con nằm trong nó, chẳng hạn như sắp xếp các View
theo chiều dọc/ngang, hoặc theo dạng bảng…
Android định nghĩa một tập các thẻ XML tương ứng với các lớp View
và ViewGroup
để chúng ta có thể thiết kế giao diện theo cú pháp XML một cách dễ dàng.
Từ lớp gốc ViewGroup,
các lớp con kế thừa được gọi với tên là Layout. Trong phần này chúng ta sẽ làm việc với LinearLayout.
Tạo LinearLayout
Chúng ta dùng thẻ LinearLayout
trong file main.xml
như sau:
<LinearLayout 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:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout>
Lớp LinearLayout
kế thừa từ lớp ViewGroup,
lớp này sẽ sắp xếp các View
con theo chiều ngang hoặc chiều dọc. Các phần tử sẽ được sắp xếp theo thứ tự mà chúng được khai báo trong file XML này.
android:orientation="horizontal"
Thuộc tính android:orientation
sẽ quy định là sắp xếp theo chiều ngang hay dọc, ở đây horizontal
là ngang, còn vertical
sẽ là dọc.
android:layout_width="match_parent" android:layout_height="match_parent"
Hai thuộc tính android:layout_width
và android:layout_height
là bắt buộc phải có, 2 thuộc tính này sẽ quy định kích thước cho đối tượng View.
Giá trị "match_parent"
tức là kích thước của View
con sẽ bằng kích thước của View
cha, nhưng vì LinearLayout
là lớp View
gốc, tức là lớp này không có View
cha nào cả nên ở đây lớp LinearLayout
này sẽ có kích thước bằng với kích thước màn hình.
Thêm TextField
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/edit_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="@string/edit_message" /> </LinearLayout>
Chúng ta thêm thẻ EditText
vào bên trong thẻ LinearLayout.
android:id="@+id/edit_message"
Thuộc tính android:id
là một cái tên riêng dành cho đối tượng View
mà chúng ta đã khai báo, chúng ta có thể tham chiếu tới id
này giống như tham chiếu tới biến trong các file .java. Dấu @
có nghĩa là giá trị của biến này được định nghĩa trong các đối tượng resource (tiếng Anh là tài nguyên) chứ không khai báo trực tiếp ở đây, theo sau dấu @
là loại resource, ở đây là id,
tiếp theo là dấu / và tên resouce edit_message.
Dấu + phía trước id
có nghĩa là tại đây chúng ta định nghĩa luôn id
chứ mặc định Android không biết id
là cái gì cả. Khi chúng ta dịch project thì SDK sẽ nhìn cái id đó và định nghĩa một lớp có tên là ID bên trong file gen/R.java,
các resource có cùng loại id sau này sẽ tự động được thêm vào ở lớp ID này để gán vào các thẻ View
của chúng ta. Khi chúng ta định nghĩa một loại resource mà có dấu + thì các resource sau này có cùng loại không cần phải có dấu + nữa.
android:layout_width="wrap_content" android:layout_height="wrap_content"
Hai thuộc tính layout_width
và layout_height
cũng giống với LinearLayout,
nhưng ở đây chúng ta sử dụng giá trị wrap_content, giá trị này quy định kích thước của View là vừa đủ để bọc lấy nội dung bên trong nó, chẳng hạn như EditText có 3 kí tự thì kích thước sẽ tự động co dãn để vừa khớp với 3 kí tự đó.
android:hint="@string/edit_message"
Thuộc tính android:hint
sẽ hiển thị một chuỗi mặc định nếu chúng ta không gõ gì vào text field. Ở đây giá trị của thuộc tính này tham chiếu tới biến edit_message
trong loại resource là string,
đây là loại resource có sẵn trong file strings.xml
của project nên chúng ta không cần phải thêm dấu + vào làm gì, nhưng chúng ta phải khai báo biến edit_message
trong file này, chúng ta sẽ khai báo ở dưới.
Mặc dù cả 2 thuộc tính android:id
và android:hint
đều tham chiếu tới resource có cùng tên là edit_message
nhưng đây là 2 resource khác nhau vì chúng nằm trong 2 loại resource khác nhau là id
và string.
Khai báo tài nguyên string
Mặc định khi tạo project Android thì project này có một file resource chứa loại string
là res/values/strings.xml.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">MainActivity</string> <string name="edit_message">Enter a message</string> <string name="button_send">Send</string> <string name="action_settings">Settings</string> </resources>
Chúng ta sẽ khai báo thêm một số resource ở đây.
<string name="edit_message">Enter a message</string>
Dòng code trên là cách khai báo một resource có kiểu là string
với tên là edit_message,
giá trị là Enter
a message.
Thường thì khi thiết kế giao diện mà có những giá trị text thì chúng ta nên khai báo bằng biến trong file resource chứ không nên khai báo trực tiếp, tức là thay vì khai báo android:hint="Enter
a
message"
thì chúng ta nên khai báo android:hint="@string/edit_message"
hơn, rồi trong file strings.xml
chúng ta khai báo thẻ string
với name
là edit_message.
Điều này giúp chúng ta dễ dàng sửa đổi cũng như cập nhật lại sau này.
Thêm Button
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/edit_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="@string/edit_message" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_send"/> </LinearLayout>
Chúng ta thêm một đối tượng View
là Button.
Các thuộc tính của thẻ Button
cũng giống các thuộc tính của 2 thẻ kia, chỉ khác ở chỗ là ở đây chúng ta không khai báo id,
thuộc tính id
là một thuộc tính không bắt buộc.
Hiện tại giao diện của ứng dụng mà chúng ta đã thiết kế sẽ như hình bên dưới.
Nhìn thì có vẻ không có vấn đề gì, nhưng nếu chúng ta nhập một chuỗi có chiều dài lớn hơn kích thước màn hình thì text field sẽ tự dãn ra và đẩy button biến mất.
Để giải quyết vấn đề này chúng ta có thể dùng đến thuộc tính android:layout_weight,
thuộc tính này quy định kích thước của các View
theo tỉ lệ.
Ví dụ nếu chúng ta khai báo EditText
có weight
là 2 và Button
có weight
là 1, như thế màn hình sẽ được chia làm 1 + 2 = 3
phần, trong đó EditText
sẽ chiếm 2 phần và Button
sẽ chiếm 1 phần. Khi chạy ứng dụng thì các View
sẽ tự động dãn ra để lấp vừa 3 phần đó, nhưng dãn vừa đủ để EditText
vẫn chiếm 2/3 kích thước còn Button
chiếm 1/3 kích thước.
Chúng ta sửa lại main.xml
như sau:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/edit_message" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="@string/edit_message" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_send"/> </LinearLayout>
Mặc định thuộc tính weight
của các View
là 0, nếu chúng ta khai báo weight
cho View
nào lớn hơn 0 thì view đó sẽ tự động dãn kích thước ra để lấp đầy khoảng trống còn thừa. Ở đây chúng ta khai báo weight cho EditText
là 1.
android:layout_width="0dp"
Ngoài ra ở đây chúng ta cũng thiết lập lại thuộc tính android:layout_width
của EditText
là 0 bởi vì mặc định wrap_content
sẽ yêu cầu ứng dụng phải tính toán kích thước của View
dựa trên số lượng kí tự trong đó, nhưng sau đó thuộc tính weight
lại yêu cầu ứng dụng dãn EditText
ra để vừa khít với phần kích thước còn thừa, như thế việc tính toán kích thước của wrap_content
là chẳng để làm gì cả, do đó chúng ta thiết lập “đại” sẵn một con số cụ thể nào đó luôn để ứng dụng khỏi mất công tính nữa, như thế sẽ tăng tốc độ thực thi của ứng dụng lên rất nhiều.
Chúng ta biên dịch và chạy lại ứng dụng với giao diện mới như hình trên.