lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

Bố trí

Bố trí định nghĩa cấu trúc hiển thị cho một giao diện người dùng, chẳng hạn như UI cho một hoạt động hoặc widget ứng dụng. Bạn có thể khai báo một bố trí bằng hai cách:

  • Khai báo phần tử UI trong XML. Android cung cấp một kho từ vựng XML đơn giản, tương ứng với các lớp và lớp con Dạng xem, chẳng hạn như dành cho các widget và bố trí.
  • Khởi tạo các phần tử bố trí vào thời gian chạy. Ứng dụng của bạn có thể tạo các đối tượng Dạng xem và Nhóm Dạng xem (và thao tác trên các tính chất của nó) theo lập trình.

Khuôn khổ Android cho bạn sự linh hoạt trong khi sử dụng một hoặc cả hai phương pháp này để khai báo và quản lý UI ứng dụng của mình. Ví dụ, bạn có thể khai báo các bố trí mặc định cho ứng dụng của mình trong XML, bao gồm các phần tử màn hình mà sẽ xuất hiện trong chúng hoặc tính chất của chúng. Sau đó, bạn có thể thêm mã trong ứng dụng của mình để sửa đổi trạng thái của các đối tượng trên màn hình, bao gồm những đối tượng được khai báo trong XML, vào thời gian chạy.

Ưu điểm của việc khai báo UI của bạn trong XML là cho phép bạn tách việc trình bày ứng dụng của mình với mã điều khiển hành vi của nó hiệu quả hơn. Mô tả UI của bạn nằm ngoài mã ứng dụng của bạn, điều này có nghĩa rằng bạn có thể sửa đổi hoặc điều hợp nó mà không phải sửa đổi mã nguồn của bạn và biên dịch lại. Ví dụ, bạn có thể tạo bố trí XML cho các hướng màn hình khác nhau, kích cỡ màn hình khác nhau, và ngôn ngữ khác nhau. Ngoài ra, việc khai báo bố trí trong XML giúp dễ dàng hơn trong việc hiển thị cấu trúc UI của bạn, vì vậy sẽ dễ gỡ lỗi sự cố hơn. Như vậy, tài liệu này tập trung vào việc hướng dẫn bạn cách khai báo bố trí của mình trong XML. Nếu bạn quan tâm tới việc khởi tạo các đối tượng Dạng xem vào thời gian chạy, hãy tham khảo ViewGroup và tài liệu tham khảo lớp View.

Nhìn chung, kho từ vựng của XML đối với việc khai báo các phần tử UI tuân thủ chặt chẽ cấu trúc và cách đặt tên các lớp và phương pháp, trong đó các tên phần tử tương ứng với tên lớp và tên thuộc tính tương ứng với phương pháp. Trên thực tế, sự tương ứng thường trực tiếp đến mức bạn có thể đoán thuộc tính XML nào tương ứng với một phương pháp lớp, hoặc đoán xem lớp nào tương ứng với một phần tử XML cho trước. Tuy nhiên, lưu ý rằng không phải tất cả từ vựng đều giống nhau. Trong một số trường hợp, có sự khác biệt nhỏ trong việc đặt tên. Ví dụ, phần tử EditText có thuộc tính text tương ứng với EditText.setText().

Mẹo: Tìm hiểu thêm về các kiểu bố trí trong Đối tượng Bố trí Thường gặp. Có một tuyển tập các bài hướng dẫn về việc xây dựng các bố trí khác nhau trong hướng dẫn bài học Dạng xem Hello.

Ghi XML

Khi sử dụng từ vựng XML của Android, bạn có thể nhanh chóng thiết kế các bố trí UI và phần tử màn hình mà chúng chứa, giống như cách bạn tạo trang web trong HTML — bằng một loạt các phần tử lồng nhau.

Mỗi tệp bố trí phải chứa chính xác một phần tử gốc, đó phải là một đối tượng Dạng xem hoặc Nhóm Dạng xem. Sau khi đã định nghĩa phần tử gốc, bạn có thể thêm các đối tượng hoặc widget bố trí bổ sung làm phần tử con để dần dần xây dựng một phân cấp Dạng xem định nghĩa bố trí của bạn. Ví dụ, sau đây là một bố trí XML sử dụng một LinearLayout thẳng đứng để giữ một TextView và một 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ố trí của mình trong XML, hãy lưu tệp với phần mở rộng .xml, trong thư mục dự án res/layout/ Android của bạn để biên dịch cho phù hợp.

Thông tin về cú pháp đối với tệp XML bố trí có sẵn trong tài liệu Tài nguyên Bố trí.

Nạp Tài nguyên XML

Khi bạn biên dịch ứng dụng của mình, từng tệp bố trí XML được biên dịch thành một tài nguyên View. Bạn nên nạp tài nguyên bố trí từ mã ứng dụng của mình, trong triển khai gọi lại Activity.onCreate() của bạn. Làm vậy bằng cách gọi setContentView(), chuyển cho nó tham chiếu tới tài nguyên bố trí của bạn dưới hình thức: R.layout.layout_file_name. Ví dụ, nếu bố trí XML của bạn được lưu thành main_layout.xml, bạn sẽ nạp nó cho Hoạt động của mình như sau:

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ủa bạn được gọi bởi khuôn khổ Android khi Hoạt động của bạn được khởi chạy (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 Dạng xem và Nhóm Dạng xem đều hỗ trợ các phiên bản thuộc tính XML của chính mình. Một số thuộc tính áp dụng riêng cho đối tượng Dạng xem (ví dụ, TextView hỗ trợ thuộc tính textSize ), nhưng những thuộc tính này cũng được kế thừa bởi bất kỳ đối tượng Dạng xem nào mà có thể mở rộng lớp này. Một số được áp dụng chung cho tất cả đối tượng Dạng xem vì chúng được kế thừa từ lớp Dạng xem gốc (như thuộc tính id). Và những thuộc tính còn lại được coi là "tham số bố trí," đó là những thuộc tính mô tả một số hướng bố trí nhất định của đối tượng Dạng xem, như được định nghĩa bởi đối tượng Nhóm Dạng xem mẹ của đối tượng đó.

ID

Bất kỳ đối tượng Dạng xem nào cũng có một ID số nguyên được liên kết với nó để nhận biết duy nhất Dạng xem trong cây. Khi ứng dụng được biên dịch, ID này được tham chiếu như một số nguyên, nhưng ID thường được gán trong tệp XML bố trí như một xâu, trong thuộc tính id. Đây là thuộc tính XML chung cho tất cả đối tượng Dạng xem (được định nghĩa theo lớp View) và bạn sẽ rất hay sử dụng nó. Cú pháp đối với một ID bên trong một tag XML là:

android:id="@+id/my_button"

Biểu tượng "a móc" (@) ở đầu xâu thể hiện rằng trình phân tích XML nên phân tích và mở rộng phần còn lại của xâu ID và nhận biết nó như một tài nguyên ID. Biểu tượng dấu cộng (+) có nghĩa rằng đây là một tên tài nguyên mới mà phải được tạo và thêm vào tài nguyên của chúng ta (trong tệp R.java). Có nhiều tài nguyên ID khác được cung cấp bởi khuôn khổ Android. Khi tham chiếu một ID tài nguyên Android, bạn không cần biểu tượng dấu cộng, nhưng phải thêm vùng tên gói android, như sau:

android:id="@android:id/empty"

Khi đã có vùng tên gói android, giờ chúng ta đang tham chiếu một ID từ lớp tài nguyên android.R , thay vì lớp tài nguyên cục bộ.

Để tạo các dạng xem và tham chiếu chúng từ ứng dụng, một mô thức thường thấy đó là:

  1. Định nghĩa một dạng xem/widget trong tệp bố trí và gán cho nó một ID duy nhất:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
    
  2. Sau đó, tạo một thực thể của đối tượng dạng xem và chụp nó từ bố trí (thường trong phương pháp onCreate()):
    Button myButton = (Button) findViewById(R.id.my_button);
    

Định nghĩa các ID cho đối tượng dạng xem là việc quan trọng khi tạo một RelativeLayout. Trong một bố trí tương đối, các dạng xem đồng hạng có thể định nghĩa bố trí của nó so với dạng xem đồng hạng kia, dạng xem mà được tham chiếu bởi ID duy nhất.

Một ID không cần phải là duy nhất trong toàn bộ cây, nhưng nên là duy nhất trong bộ phận của cây mà bạn đang tìm kiếm (thường là toàn bộ cây, vì thế tốt nhất là ID nên hoàn toàn duy nhất khi có thể).

Tham số Bố trí

Các thuộc tính bố trí XML layout_something sẽ định nghĩa các tham số bố trí cho Dạng xem phù hợp với Nhóm Dạng xem mà nó nằm trong đó.

Mọi lớp Nhóm Dạng xem đều triển khai một lớp lồng nhau có chức năng mở rộng ViewGroup.LayoutParams. Lớp con này chứa các kiểu tính chất mà định nghĩa kích cỡ và vị trí của từng dạng xem con cho phù hợp với nhóm dạng xem. Như bạn có thể thấy trong hình 1, nhóm dạng xem mẹ sẽ định nghĩa các tham số bố trí cho từng dạng xem con (bao gồm nhóm dạng xem con).

Hình 1. Trực quan hóa một phân cấp dạng xem với các tham số bố trí được liên kết với từng dạng xem.

Để ý rằng mọi lớp con LayoutParams đều có cú pháp riêng của mình cho các giá trị thiết đặt. Mỗi phần tử con phải định nghĩa LayoutParams cho phù hợp với phần tử mẹ của nó, mặc dù cũng có thể định nghĩa LayoutParams khác cho phần tử con của chính nó.

Tất cả nhóm dạng xem đều có chiều rộng và chiều cao (layout_widthlayout_height), và mỗi dạng xem đều phải định nghĩa chúng. Nhiều LayoutParams cũng có lề và viền tùy 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 sẽ không muốn làm điều này thường xuyên. Bạn sẽ thường sử dụng một trong những hằng số này để đặt chiều rộng hoặc chiều cao:

  • wrap_content cho biết dạng xem của bạn tự định cỡ theo kích thước mà nội dung của nó yêu cầu.
  • match_parent (được đặt tên fill_parent trước API Mức 8) cho biết dạng xem của bạn có thể phóng lớn khi nhóm dạng xem mẹ của nó cho phép.

Nhìn chung, việc chỉ định một chiều rộng và chiều cao bố trí bằng cách sử dụng các đơn vị tuyệt đối như điểm ảnh là điều không được khuyến cáo. Thay vào đó, sử dụng các số đo tương đối như số đơn vị điểm ảnh độc lập với mật độ (dp), wrap_content, hoặc match_parent, là một phương pháp tốt hơn, vì nó giúp đảm bảo rằng ứng dụng của bạn sẽ hiển thị phù hợp giữa nhiều loại kích cỡ màn hình thiết bị khác nhau. Các kiểu số đo được chấp nhận được định nghĩa trong tài liệu Tài nguyên Có sẵn.

Vị trí Bố trí

Hình học của một dạng xem là hình chữ nhật. Dạng xem có một vị trí, được biểu diễn thành một cặp tọa độ tráitrên và hai kích thước, được biểu diễn thành chiều rộng và chiều cao. Đơn vị của vị trí và kích thước là điểm ảnh.

Có thể truy xuất vị trí của một dạng xem bằng cách gọi ra các phương pháp getLeft()getTop(). Phương pháp đầu trả về tọa độ trái, hay X, của hình chữ nhật biểu diễn dạng xem. Phương pháp sau trả về tọa độ trên, hay Y, của hình chữ nhật biểu diễn dạng xem. Những phương pháp này đều trả về vị trí của dạng xem so với dạng xem mẹ của nó. Ví dụ, khi getLeft() trả về 20, điều đó có nghĩa là dạng xem nằm ở 20 điểm ảnh về bên phải của cạnh trái của dạng xem mẹ trực tiếp của nó.

Ngoài ra, một vài phương pháp thuận tiện được đưa ra để tránh những tính toán không cần thiết, cụ thể là getRight()getBottom(). Những phương pháp này trả về tọa độ của cạnh phải và cạnh đáy của hình chữ nhật biểu diễn dạng xem. Ví dụ, việc gọi getRight() tương tự như tính toán sau: getLeft() + getWidth().

Kích cỡ, Phần đệm và Lề

Kích cỡ của một dạng xem được biểu diễn bằng chiều rộng và chiều cao. Thực ra một dạng xem sẽ có hai cặp giá trị chiều rộng và chiều cao.

Cặp thứ nhất được gọi là chiều rộng đo đượcchiều cao đo được. Những kích thước này xác định một dạng xem muốn phóng lớn bao nhiêu trong dạng xem mẹ của nó. Các kích thước đo được có thể thu được bằng cách gọi getMeasuredWidth()getMeasuredHeight().

Cặp thứ hai đơn thuần là chiều rộngchiều cao, hoặc đôi khi gọi là chiều rộng vẽchiều cao vẽ. Những kích thước này xác định kích cỡ thực sự của dạng xem trên màn hình, tại thời điểm vẽ và sau khi bố trí. Những giá trị này có thể nhưng không nhất thiết phải khác với chiều rộng và chiều cao đo được. Chiều rộng và chiều cao này có thể lấy được bằng cách gọi getWidth()getHeight().

Để đo các kích thước của nó, dạng xem cần xét tới phần đệm của nó. Phần đệm được biểu diễn bằng số điểm ảnh của phần bên trái, bên trên, bên phải và bên dưới của dạng xem. Phần đệm có thể được sử dụng để bù trừ nội dung của dạng xem bằng một số điểm ảnh cụ thể. Ví dụ, phần đệm bên trái bằng 2 sẽ đẩy nội dung của dạng xem đi 2 điểm ảnh về bên phải của cạnh bên trái. Phần đệm có thể được đặt bằng cách sử dụng phương pháp setPadding(int, int, int, int) và được truy vấn bằng cách gọi getPaddingLeft(), getPaddingTop(), getPaddingRight()getPaddingBottom().

Mặc dù dạng xem có thể xác định phần đệm, nó không có bất kỳ sự hỗ trợ nào cho lề. Tuy nhiên, các nhóm dạng xem lại cung cấp sự hỗ trợ như vậy. Tham khảo ViewGroupViewGroup.MarginLayoutParams để biết thêm thông tin.

Để biết thêm thông tin về kích thước, xem Giá trị Kích thước.

Các Bố trí Thường gặp

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 dạng xem mà bạn lồng trong nó. Dưới đây là một số kiểu bố trí phổ biến hơn mà được tích hợp trong nền tảng Android.

Lưu ý: Mặc dù bạn có thể lồng một hoặc nhiều bố trí với một bố trí khác để đạt được thiết kế UI của mình, bạn nên cố gắng duy trì phân cấp bố trí của mình ở mức nông nhất có thể. Bố trí của bạn sẽ vẽ nhanh hơn nếu nó có ít bố trí lồng nhau hơn (phân cấp dạng xem rộng sẽ tốt hơn phân cấp dạng xem sâu).

Bố trí Tuyến tính

Một bố trí có chức năng sắp xếp tổ chức các bố trí con của nó thành một hàng ngang hoặc thẳng đứng. Nó sẽ tạo một thanh cuộn nếu chiều dài của cửa sổ vượt quá chiều dài của màn hình.

Bố trí Tương đối

Cho phép bạn chỉ định vị trí của các đối tượng con so với nhau (đối tượng con A về phí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 bên trên đối tượng mẹ).

Dạng xem Web

Hiển thị trang web.

Xây dựng Bố trí bằng một Trình điều hợp

Khi nội dung cho bố trí của bạn động hoặc chưa được xác định trước, bạn có thể sử dụng một bố trí có chức năng tạo lớp con AdapterView để đưa vào bố trí có dạng xem vào thời gian chạy. Một lớp con của lớp AdapterView sẽ sử dụng một Adapter để gắn kết dữ liệu với bố trí của nó. Adapter đóng vai trò trung gian giữa nguồn dữ liệu và bố trí AdapterViewAdapter sẽ truy xuất dữ liệu (từ một nguồn chẳng hạn như một mảng hoặc truy vấn cơ sở dữ liệu) và chuyển từng mục nhập thành một dạng xem có thể thêm vào bố trí AdapterView.

Các bố trí phổ biến được hỗ trợ bởi trình điều hợp bao gồm:

Dạng xem Danh sách

Hiển thị một danh sách cột cuộn đơn.

Dạng xem Lưới

Hiển thị một lưới cuộn gồm nhiều hàng và cột.

Điền dữ liệu vào một dạng xem trình điều hợp

Bạn có thể đưa vào một AdapterView chẳng hạn như ListView hoặc GridView bằng cách gắn kết thực thể AdapterView với một Adapter, nó truy xuất dữ liệu từ một nguồn bên ngoài và tạo một View để biểu diễn từng mục nhập dữ liệu.

Android cung cấp một vài lớp con của Adapter rất hữu ích cho việc truy xuất các kiểu dữ liệu khác nhau và xây dựng dạng xem cho một AdapterView. Hai trình điều hợp phổ biến nhất là:

ArrayAdapter
Sử dụng trình điều hợp 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 dạng xem cho mỗi mục mảng bằng cách gọi toString() trên từng mục và đặt nội dung trong một TextView.

Ví dụ, nếu bạn có một mảng xâu mà bạn muốn hiển thị trong một ListView, hãy khởi tạo một ArrayAdapter mới bằng cách sử dụng hàm dựng để chỉ định bố trí cho từng xâu và mảng xâu:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, myStringArray);

Các tham đối cho hàm dựng này là:

  • Ứng dụng của bạn Context
  • Bố trí chứa một TextView cho mỗi xâu trong mảng
  • Mảng xâu

Sau đó chỉ cần gọi setAdapter() trên ListView của bạn:

ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);

Để tùy chỉnh diện mạo của từng mục, bạn có thể khống chế phương pháp toString() cho các đối tượng trong mảng của mình. Hoặc, để tạo một dạng xem cho từng mục không phải là một TextView (ví dụ, nếu bạn muốn một ImageView cho từng mục mảng), hãy mở rộng lớp ArrayAdapter và khống chế getView() để trả về kiểu dạng xem mà bạn muốn cho từng mục.

SimpleCursorAdapter
Sử dụng trình điều hợp này khi dữ liệu của bạn đến từ một Cursor. Khi sử dụng SimpleCursorAdapter, bạn phải chỉ định một bố trí để sử dụng cho từng hàng trong Cursor và những cột nào trong Cursor nên được chèn vào dạng xem nào của bố trí. Ví dụ, nếu bạn muốn tạo một danh sách tên người và số điện thoại, bạn có thể thực hiện một truy vấn mà trả về một Cursor chứa một hàng cho từng người và nhiều cột cho các tên và số điện thoại. Sau đó, bạn tạo một mảng xâu chỉ định những cột nào từ Cursor mà bạn muốn trong bố trí cho từng kết quả và một mảng số nguyên chỉ định các dạng xem tương ứng mà từng cột sẽ được đặt vào:

String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
                        ContactsContract.CommonDataKinds.Phone.NUMBER};
int[] toViews = {R.id.display_name, R.id.phone_number};

Khi bạn khởi tạo SimpleCursorAdapter, hãy chuyển bố trí cần sử dụng cho từng kết quả, Cursor chứa các kết quả, và hai mảng sau:

SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
        R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
ListView listView = getListView();
listView.setAdapter(adapter);

Sau đó, SimpleCursorAdapter tạo một dạng xem cho từng hàng trong Cursor sử dụng bố trí được cung cấp bằng cách chèn từng mục fromColumns vào dạng xem toViews tương ứng.

.

Trong vòng đời ứng dụng của bạn, nếu bạn thay đổi dữ liệu liên quan được đọc bởi trình điều hợp của mình, bạn nên gọi notifyDataSetChanged(). Nó sẽ thông báo với dạng xem đính kèm rằng dữ liệu đã được thay đổi và dạng xem nên tự làm mới.

Xử lý sự kiện nhấp

Bạn có thể phản hồi các sự kiện nhấp trên từng mục trong một AdapterView bằng cách triển khai giao diện AdapterView.OnItemClickListener. Ví dụ:

// Create a message handling object as an anonymous class.
private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id) {
        // Do something in response to the click
    }
};

listView.setOnItemClickListener(mMessageClickedHandler);