Bố cục Thuộc Android Jetpack.
Bố cục xác định cấu trúc cho giao diện người dùng trong ứng dụng, chẳng hạn như trong một hoạt động.
Tất cả các phần tử trong bố cục đều được tạo bằng một hệ phân cấp gồm các đối tượng View
và
ViewGroup
. View
thường
dựng nội dung mà người dùng có thể nhìn thấy và tương tác cùng. Trong khi đó, ViewGroup
là
một vùng chứa vô hình xác định cấu trúc bố cục cho View
và các đối tượng
ViewGroup
khác, như minh hoạ trong hình 1.

Hình 1. Hình minh hoạ hệ phân cấp thành phần hiển thị, hệ thống này xác định bố cục giao diện người dùng
Các đối tượng View
thường được gọi là các "tiện ích" và có thể là một trong nhiều
lớp con, chẳng hạn như Button
hoặc TextView
. Đối tượng
ViewGroup
thường được gọi là "bố cục", có thể là một trong nhiều loại
cung cấp một cấu trúc bố cục khác, chẳng hạn như LinearLayout
hoặc
ConstraintLayout
.
Bạn có thể khai báo một bố cục theo 2 cách:
- Khai báo các thành phần trên giao diện người dùng ở định dạng XML. Android cung cấp từ vựng XML
đơn giản, tương ứng với các lớp và lớp con Thành phần hiển thị, chẳng hạn như lớp và lớp con cho các tiện ích và
bố cục.
Bạn cũng có thể sử dụng Layout Editor của Android Studio để tạo bố cục XML bằng giao diện kéo và thả.
- Tạo bản sao của các phần tử bố cục trong thời gian chạy. Ứng dụng của bạn có thể tạo các đối tượng View và ViewGroup (và điều khiển các thuộc tính của các đối tượng đó) theo phương thức lập trình.
Việc khai báo giao diện người dùng trong XML cho phép bạn tách riêng bản trình bày của ứng dụng khỏi mã kiểm soát hành vi của ứng dụng đó. Việc sử dụng tệp XML cũng giúp bạn dễ dàng cung cấp nhiều bố cục cho nhiều kích thước và hướng màn hình (trình bày cụ thể trong bài viết Hỗ trợ nhiều kích thước màn hình).
Khung Android giúp bạn sử dụng linh hoạt một trong hai hoặc cả hai phương thức này để tạo giao diện người dùng cho ứng dụng của mình. Ví dụ: bạn có thể khai báo các bố cục mặc định cho ứng dụng trong XML, sau đó chỉnh sửa bố cục trong thời gian chạy.
Mẹo: Để gỡ lỗi bố cục trong thời gian chạy, hãy sử dụng công cụ Layout Inspector.
Ghi XML
Bằng cách sử dụng từ vựng XML của Android, bạn có thể nhanh chóng thiết kế bố cục giao diện người dùng và các phần tử màn hình trong bố cục, giống như cách bạn tạo trang web trong HTML — với một loạt các phần tử lồng nhau.
Mỗi tệp bố cục phải chứa đúng một phần tử gốc và phải là đối tượng View hoặc ViewGroup. Khi đã xác định được phần tử gốc, bạn có thể thêm các đối tượng hoặc tiện ích bố cục bổ sung làm các phần tử con để từng bước tạo một hệ phân cấp thành phần hiển thị xác định bố cục. Ví dụ: dưới đây là một bố cục XML sử dụng một LinearLayout
dọc
để giữ một TextView
và Button
:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout>
Sau khi bạn khai báo bố cục trong XML, hãy lưu tệp có phần mở rộng .xml
trong thư mục res/layout/
của dự án Android để tệp này được biên dịch đúng cách.
Bạn có thể tìm thêm thông tin về cú pháp cho tệp XML bố cục trong tài liệu Tài nguyên bố cục.
Tải tài nguyên XML
Khi bạn biên dịch ứng dụng, mỗi tệp bố cục XML sẽ được biên dịch thành
tài nguyên View
. Bạn nên tải tài nguyên bố cục từ mã ứng dụng trong hoạt động triển khai lệnh gọi lại
Activity.onCreate()
.
Hãy thực hiện việc đó bằng cách gọi
,
chuyển tham chiếu đến tài nguyên bố cục ở dạng:
setContentView()
R.layout.layout_file_name
.
Ví dụ: nếu bố cục XML của bạn được lưu là main_layout.xml
, bạn sẽ tải bố cục đó
cho Hoạt động như sau:
Kotlin
fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.main_layout) }
Java
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); }
Phương pháp gọi lại onCreate()
trong Hoạt động được gọi bằng khung Android khi
khởi chạy Hoạt động của bạn (xem phần thảo luận về vòng đời trong
tài liệu
Hoạt động).
Thuộc tính
Mỗi đối tượng View và ViewGroup đều hỗ trợ nhiều thuộc tính XML riêng.
Một số thuộc tính dành riêng cho một đối tượng View (ví dụ: TextView hỗ trợ thuộc tính textSize
),
nhưng bất kỳ đối tượng View nào mở rộng lớp này cũng có thể kế thừa các thuộc tính này.
Có một số thuộc tính phổ biến với tất cả các đối tượng View vì những đối tượng này được kế thừa từ lớp View gốc (như
thuộc tính id
). Và các thuộc tính khác được coi là "thông số bố cục", là các thuộc tính
mô tả một số hướng bố cục của đối tượng View, như được xác định bằng đối tượng ViewGroup gốc
của đối tượng đó.
Mã nhận dạng
Bất kỳ đối tượng View nào cũng có thể có một mã nhận dạng dưới dạng số nguyên liên kết với nó, để nhận dạng duy nhất View đó trong cây.
Khi ứng dụng được biên dịch, mã nhận dạng này được tham chiếu dưới dạng số nguyên, nhưng mã này thường
được chỉ định trong tệp XML bố cục dưới dạng một chuỗi, trong thuộc tính id
.
Đây là một thuộc tính XML phổ biến đối với tất cả các đối tượng View
(do lớp View
xác định) và bạn sẽ sử dụng thuộc tính này rất thường xuyên.
Cú pháp cho mã nhận dạng, bên trong thẻ XML là:
android:id="@+id/my_button"
Ký hiệu at (@) ở đầu chuỗi cho biết rằng trình phân tích cú pháp XML sẽ phân tích cú pháp và mở rộng phần còn lại
của chuỗi mã nhận dạng và xác định chuỗi đó là tài nguyên mã nhận dạng. Ký hiệu dấu cộng (+) cho biết đây là tên tài nguyên mới
phải được tạo và thêm vào tài nguyên của chúng tôi (trong tệp R.java
). Khung Android này cung cấp một số
tài nguyên mã nhận dạng khác. Khi tham chiếu mã nhận dạng tài nguyên Android, bạn không cần thêm ký hiệu dấu cộng,
nhưng phải thêm không gian tên gói android
như sau:
android:id="@android:id/empty"
Sau khi thêm không gian tên gói android
, chúng ta sẽ tham chiếu một mã nhận dạng từ lớp tài nguyên android.R
,
thay vì lớp tài nguyên cục bộ.
Để tạo các thành phần hiển thị và tham chiếu chúng từ ứng dụng, có một quy trình chung là:
- Xác định một thành phần hiển thị/tiện ích trong tệp bố cục và chỉ định một mã nhận dạng duy nhất cho thành phần hiển thị/tiện ích đó:
<Button android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/my_button_text"/>
- Sau đó, hãy tạo một bản sao của đối tượng thành phần hiển thị và thu bản sao từ bố cục
(thường là trong phương thức
):onCreate()
Kotlin
val myButton: Button = findViewById(R.id.my_button)
Java
Button myButton = (Button) findViewById(R.id.my_button);
Bạn cần xác định mã nhận dạng cho đối tượng thành phần hiển thị khi tạo RelativeLayout
.
Trong một bố cục tương đối, các thành phần hiển thị đồng cấp có thể xác định bố cục của chúng so với một thành phần hiển thị đồng cấp khác,
được tham chiếu theo mã nhận dạng duy nhất.
Mã nhận dạng không cần phải là duy nhất trong toàn bộ cây, nhưng phải là duy nhất trong một phần của cây mà bạn đang tìm kiếm (thường có thể là toàn bộ cây, vì vậy tốt nhất nên là mã nhận dạng duy nhất tuyệt đối nếu có thể).
Lưu ý: Với Android Studio 3.6 trở lên,
tính năng liên kết thành phần hiển thị có thể thay thế
lệnh gọi findViewById()
và cung cấp sự an toàn kiểu thời gian biên dịch cho
mã tương tác với thành phần hiển thị. Cân nhắc sử dụng liên kết thành phần hiển thị thay vì
findViewById()
.
Thông số bố cục
Các thuộc tính bố cục XML có tên layout_something
xác định
các thông số bố cục cho View phù hợp với ViewGroup chứa View đó.
Mỗi lớp ViewGroup sẽ triển khai một lớp lồng ghép mở rộng ViewGroup.LayoutParams
. Lớp con này
chứa các loại thuộc tính xác định kích thước và vị trí cho mỗi thành phần hiển thị con,
phù hợp với nhóm thành phần hiển thị. Như bạn có thể thấy trong hình 2, nhóm thành phần hiển thị gốc
xác định các thông số bố cục cho mỗi thành phần hiển thị con (bao gồm cả nhóm thành phần hiển thị con).

Hình 2. Hình ảnh minh họa hệ phân cấp thành phần hiển thị với các thông số bố cục liên kết với mỗi thành phần hiển thị
Hãy lưu ý rằng mọi lớp con LayoutParams đều có cú pháp riêng để đặt giá trị. Mỗi phần tử con phải xác định LayoutParams phù hợp với phần tử gốc, mặc dù phần tử con này cũng có thể xác định các LayoutParams khác nhau cho các phần tử con của nó.
Tất cả các nhóm thành phần hiển thị đều có chiều rộng và chiều cao (layout_width
và
layout_height
) và mỗi thành phần hiển thị phải xác định các thông số này. Nhiều
LayoutParams cũng bao gồm lề và đường viền tuỳ chọn.
Bạn có thể chỉ định chiều rộng và chiều cao bằng các số đo chính xác, mặc dù có thể bạn không muốn thực hiện việc này thường xuyên. Thông thường, bạn sẽ sử dụng một trong các hằng số sau để đặt chiều rộng hoặc chiều cao:
- wrap_content yêu cầu thành phần hiển thị điều chỉnh kích thước theo kích thước cần thiết cho nội dung.
- match_parent yêu cầu thành phần hiển thị mở rộng bằng với kích thước mà nhóm thành phần hiển thị gốc cho phép.
Nhìn chung, bạn không nên xác định chiều rộng và chiều cao của bố cục bằng các đơn vị tuyệt đối như pixel. Thay vào đó, bạn nên sử dụng các số đo tương đối như đơn vị pixel không phụ thuộc vào mật độ (dp), wrap_content hoặc match_parent, vì cách này giúp đảm bảo rằng ứng dụng sẽ hiển thị chính xác trên nhiều kích thước màn hình thiết bị. Tài liệu Tài nguyên có sẵn quy định các loại số đo được chấp nhận.
Vị trí bố cục
Một thành phần hiển thị có dạng hình chữ nhật. Một thành phần hiển thị có vị trí, được biểu thị bằng một cặp tọa độ bên trái và đỉnh, với hai kích thước, được biểu thị dưới dạng chiều rộng và chiều cao. Đơn vị cho vị trí và kích thước là pixel.
Bạn có thể truy xuất vị trí của một thành phần hiển thị bằng cách gọi các phương thức
getLeft()
và getTop()
. Phương thức thứ nhất trả về tọa độ bên trái (X)
của hình chữ nhật đại diện cho thành phần hiển thị. Phương thức thứ hai trả về
tọa độ đỉnh (Y) của hình chữ nhật đại diện cho thành phần hiển thị. Các phương thức này
đều trả về vị trí của thành phần hiển thị so với thành phần hiển thị gốc. Ví dụ:
khi getLeft()
trả về 20, nghĩa là thành phần hiển thị này có vị trí cách
cạnh trái của thành phần hiển thị gốc 20 pixel về bên phải.
Ngoài ra, chúng tôi cũng cung cấp một số phương thức tiện lợi giúp tránh các phép tính
không cần thiết, cụ thể là getRight()
và getBottom()
.
Các phương thức này trả về tọa độ của các cạnh bên phải và cạnh dưới cùng của
hình chữ nhật đại diện cho thành phần hiển thị. Ví dụ: lệnh gọi getRight()
tương tự như phép tính sau: getLeft() + getWidth()
.
Kích thước, khoảng đệm và lề
Kích thước của thành phần hiển thị được biểu thị bằng chiều rộng và chiều cao. Thực ra, một thành phần hiển thị có hai cặp giá trị chiều rộng và chiều cao.
Cặp giá trị đầu tiên được gọi là chiều rộng đo được và
chiều cao đo được. Các kích thước này xác định độ lớn mong muốn cho thành phần hiển thị
trong phần tử mẹ. Bạn có thể lấy
các kích thước đo được bằng cách gọi getMeasuredWidth()
và getMeasuredHeight()
.
Cặp giá trị thứ hai được gọi đơn giản là chiều rộng và chiều cao, hoặc
đôi khi là chiều rộng được vẽ và chiều cao được vẽ. Các
kích thước này xác định kích thước thực tế của thành phần hiển thị trên màn hình, tại thời điểm vẽ và
sau khi tạo bố cục. Các giá trị này có thể khác với
chiều rộng và chiều cao đo được, mặc dù không nhất thiết phải như vậy. Bạn có thể lấy chiều rộng và chiều cao bằng cách gọi
getWidth()
và getHeight()
.
Để đo các kích thước, thành phần hiển thị sẽ tính đến khoảng đệm. Khoảng đệm
được biểu thị bằng pixel cho các phần bên trái, trên cùng, bên phải và dưới cùng của thành phần hiển thị.
Có thể sử dụng khoảng đệm để bù trừ nội dung của thành phần hiển thị theo một số lượng
pixel cụ thể. Ví dụ: với khoảng đệm bên trái bằng 2 pixel, nội dung của thành phần hiển thị sẽ dịch sang bên phải
của cạnh trái một khoảng bằng 2 pixel. Bạn có thể đặt khoảng đệm bằng phương thức
setPadding(int, int, int, int)
và truy vấn khoảng đệm bằng cách gọi
getPaddingLeft()
, getPaddingTop()
,
getPaddingRight()
và getPaddingBottom()
.
Mặc dù một thành phần hiển thị có thể xác định khoảng đệm, nhưng sẽ hoàn toàn không hỗ trợ
lề. Tuy nhiên, nhóm thành phần hiển thị sẽ hỗ trợ lề. Hãy tham khảo
ViewGroup
và
ViewGroup.MarginLayoutParams
để biết thêm thông tin.
Để biết thêm thông tin về kích thước, hãy xem phần Giá trị kích thước.
Bố cục phổ biến
Mỗi lớp con của lớp ViewGroup
cung cấp một cách duy nhất để hiển thị
các thành phần hiển thị mà bạn lồng trong đó. Dưới đây là một số loại bố cục phổ biến
hơn được tích hợp
vào nền tảng Android.
Lưu ý: Mặc dù bạn có thể lồng một hoặc nhiều bố cục trong một bố cục khác để có được thiết kế giao diện người dùng ưng ý, nhưng bạn nên cố gắng tối giản hóa hệ phân cấp bố cục. Bố cục sẽ được dựng nhanh hơn nếu có ít bố cục lồng nhau hơn (hệ phân cấp thành phần hiển thị có cấu trúc rộng sẽ tốt hơn hệ phân cấp thành phần hiển thị có cấu trúc sâu).
Bố cục tuyến tính

Bố cục sắp xếp các phần tử con thành một hàng ngang hoặc dọc. Bố cục sẽ tạo một thanh cuộn nếu chiều dài cửa sổ vượt quá chiều dài màn hình.
Bố cục tương đối

Cho phép bạn xác định vị trí của đối tượng con so với các đối tượng con khác (đối tượng con A ở bên trái của đối tượng con B) hoặc so với đối tượng mẹ (được căn theo cạnh trên cùng của đối tượng mẹ).
Xây dựng bố cục bằng bộ chuyển đổi
Khi nội dung cho bố cục linh động hoặc không được xác định trước, bạn có thể sử dụng bố cục
gồm các lớp con AdapterView
để điền bố cục bằng các thành phần hiển thị trong thời gian chạy. Một
lớp con của lớp AdapterView
sử dụng Adapter
để
liên kết dữ liệu với bố cục của lớp đó. Adapter
hoạt động như một thành phần trung gian giữa nguồn
dữ liệu và bố cục AdapterView
, Adapter
truy xuất dữ liệu (từ một nguồn như mảng hoặc truy vấn cơ sở dữ liệu) và chuyển đổi mỗi mục
thành một thành phần hiển thị có thể thêm vào bố cục AdapterView
.
Các bố cục phổ biến được bộ chuyển đổi hỗ trợ bao gồm:
Điền dữ liệu vào thành phần hiển thị bộ chuyển đổi
Bạn có thể điền dữ liệu vào AdapterView
như ListView
hoặc
GridView
bằng cách liên kết bản sao AdapterView
với
Adapter
, bộ chuyển đổi này sẽ truy xuất dữ liệu từ một nguồn bên ngoài và tạo View
đại diện cho từng mục dữ liệu.
Android cung cấp một số lớp con của Adapter
rất hữu ích trong việc
truy xuất nhiều loại dữ liệu, cũng như tạo thành phần hiển thị cho AdapterView
. Hai
bộ chuyển đổi phổ biến nhất là:
ArrayAdapter
- Hãy dùng bộ chuyển đổi này khi nguồn dữ liệu của bạn là một mảng. Theo mặc định,
ArrayAdapter
tạo một thành phần hiển thị cho từng mục mảng bằng cách gọitoString()
cho từng mục và đặt nội dung trong mộtTextView
.Ví dụ: nếu bạn muốn hiển thị một mảng các chuỗi trong
ListView
, hãy khởi chạy mộtArrayAdapter
mới bằng một hàm khởi tạo để chỉ định bố cục cho từng chuỗi và mảng chuỗi:Kotlin
val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)
Java
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray);
Các đối số cho hàm khởi tạo này là:
Sau đó, bạn chỉ cần gọi
setAdapter()
trênListView
:Kotlin
val listView: ListView = findViewById(R.id.listview) listView.adapter = adapter
Java
ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(adapter);
Để tuỳ chỉnh giao diện của mỗi mục, bạn có thể ghi đè phương thức
toString()
cho các đối tượng trong mảng. Hoặc, để tạo thành phần hiển thị cho từng mục không phải làTextView
(ví dụ: nếu bạn muốn cóImageView
cho từng mục mảng), hãy mở rộng lớpArrayAdapter
và ghi đègetView()
để trả về loại thành phần hiển thị mà bạn muốn cho từng mục. SimpleCursorAdapter
- Sử dụng bộ chuyển đổi này khi dữ liệu của bạn được lấy từ
Cursor
. Khi sử dụngSimpleCursorAdapter
, bạn phải chỉ định một bố cục để sử dụng cho mỗi hàng trongCursor
, cũng như chỉ định chèn cột nào trongCursor
vào thành phần hiển thị nào của bố cục. Ví dụ: nếu muốn tạo danh sách tên và số điện thoại của mọi người, bạn có thể thực hiện truy vấn trả vềCursor
chứa một hàng cho mỗi người và cột cho tên và số điện thoại. Sau đó, bạn tạo một mảng chuỗi xác định các cột trongCursor
mà mình muốn có trong bố cục cho mỗi kết quả và một mảng số nguyên xác định các thành phần hiển thị tương ứng cần đặt cho mỗi cột:Kotlin
val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER) val toViews = intArrayOf(R.id.display_name, R.id.phone_number)
Java
String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER}; int[] toViews = {R.id.display_name, R.id.phone_number};
Khi bạn tạo bản sao của
SimpleCursorAdapter
, hãy chuyển bố cục để sử dụng cho mỗi kết quả,Cursor
chứa các kết quả và 2 mảng này:Kotlin
val adapter = SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0) val listView = getListView() listView.adapter = adapter
Java
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0); ListView listView = getListView(); listView.setAdapter(adapter);
Sau đó,
.SimpleCursorAdapter
sẽ tạo một thành phần hiển thị cho mỗi hàng trongCursor
với bố cục đã cung cấp, bằng cách chèn mỗi mụcfromColumns
vào thành phần hiển thịtoViews
tương ứng.
Nếu trong quá trình hoạt động của ứng dụng, bạn thay đổi dữ liệu cơ bản mà bộ chuyển đổi đọc ra,
bạn cần gọi notifyDataSetChanged()
. Việc này
sẽ thông báo cho thành phần hiển thị đính kèm rằng dữ liệu đã được thay đổi và sẽ tự làm mới.
Xử lý sự kiện nhấp chuột
Bạn có thể phản hồi các sự kiện nhấp của từng mục trong AdapterView
bằng cách
triển khai giao diện AdapterView.OnItemClickListener
. Ví dụ:
Kotlin
listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id -> // Do something in response to the click }
Java
// Create a message handling object as an anonymous class. private OnItemClickListener messageClickedHandler = new OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { // Do something in response to the click } }; listView.setOnItemClickListener(messageClickedHandler);
Tài nguyên khác
Các bố cục được sử dụng trong ứng dụng minh họa Sunflower.