Bố cục trong khung hiển thị

Thử cách Compose
Jetpack Compose là bộ công cụ giao diện người dùng được đề xuất cho Android. Tìm hiểu cách sử dụng bố cục trong ứng dụng Compose.

Bố cục xác định cấu trúc của 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ằng cách sử dụng hệ thống phân cấp ViewViewGroup . View thường minh hoạ nội dung mà người dùng có thể nhìn thấy và tương tác với. ViewGroup là một vùng chứa vô hình xác định cấu trúc bố cục cho ViewViewGroup khác như được minh hoạ trong Hình 1.

Hình 1. Hình minh hoạ hệ phân cấp khung hiển thị, trong đó xác định bố cục của giao diện người dùng.

Đối tượng View thường được gọi là tiện ích và có thể là một trong nhiều lớp con, chẳng hạn như Button hoặc TextView. Chiến lược phát hành đĩa đơn Các đối tượng ViewGroup thường được gọi là bố cục và có thể là một nhiều loại cung cấp một cấu trúc bố cục khác nhau, 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 một XML đơn giản từ vựng tương ứng với các lớp và lớp con View, chẳng hạn như tiện ích con và bố cục. Bạn cũng có thể sử dụng Layout Editor để tạo tệp XML của bạn bằng giao diện kéo và thả.

  • Tạo thực thể cho 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 ViewViewGroup cũng như thao tác với các đối tượng này các thuộc tính 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 bản trình bày của ứng dụng khỏi mã kiểm soát hành vi của nó. Việc sử dụng các tệp XML cũng giúp bạn dễ dàng cung cấp các bố cục khác nhau cho nhiều hướng và kích thước màn hình. Đây là sẽ được thảo luận thêm trong Hỗ trợ nhiều màn hình kích thước.

Khung Android mang đến cho bạn sự linh hoạt khi sử dụng một hoặc cả hai các phương pháp này để tạo giao diện người dùng của ứng dụng. Ví dụ: bạn có thể khai báo bố cục mặc định trong XML rồi sửa đổi bố cục trong thời gian chạy.

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 mà chúng chứa, giống như cách bạn tạo các trang web trong HTML bằng 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ần tử đó phải là Đối tượng View hoặc ViewGroup. Sau khi bạn xác định thư mục gốc , bạn có thể thêm các đối tượng bố cục hoặc tiện ích khác làm phần tử con để xây dựng dần một hệ phân cấp View xác định bố cục của bạn. Cho ví dụ: dưới đây là bố cục XML sử dụng LinearLayout dọc để 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ố cục trong XML, hãy lưu tệp bằng Tiện ích .xml trong res/layout/ của dự án Android để thư mục biên dịch đúng cách.

Để biết thêm thông tin về cú pháp cho tệp XML bố cục, hãy xem 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. Tải tài nguyên bố cục trong Activity.onCreate() lệnh gọi lại. Thực hiện điều này bằng cách gọi setContentView(), truyền tham chiếu đến tài nguyên bố cục trong biểu mẫu: R.layout.layout_file_name Ví dụ: nếu mã XML của bạn bố cục được lưu dưới dạng main_layout.xml, hãy tải bố cục này cho Activity 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);
}

Khung Android gọi phương thức gọi lại onCreate() trong Activity của bạn khi Activity khởi chạy. Để biết thêm thông tin về vòng đời hoạt động, xem Giới thiệu về hoạt động.

Thuộc tính

Mỗi đối tượng ViewViewGroup đều hỗ trợ đối tượng riêng các thuộc tính XML khác nhau. Có một số thuộc tính dành riêng cho View . Ví dụ: TextView hỗ trợ textSize . Tuy nhiên, mọi View cũng kế thừa những thuộc tính này các đối tượng mở rộng lớp này. Một số lỗi phổ biến đối với tất cả View vì các đối tượng này được kế thừa từ lớp View gốc, chẳng hạn như thuộc tính id. Các thuộc tính khác được coi là bố cục tham số, là những thuộc tính mô tả một số hướng bố cục nhất định của đối tượng View, như được xác định bởi phần tử mẹ của đối tượng đó Đối tượng ViewGroup.

ID

Mọi đối tượng View đều có thể được liên kết với một mã nhận dạng bằng số nguyên để xác định 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 chung cho mọi đối tượng View và được xác định bằng Lớp View. Bạn sử dụng mã này rất thường xuyên. Cú pháp cho một mã nhận dạng bên trong một Thẻ XML như sau:

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, đồng thời xác định chuỗi đó là tài nguyên mã nhận dạng. Dấu dấu cộng (+) có nghĩa là đâ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 bạn trong R.java .

Khung Android cung cấp nhiều tài nguyên mã nhận dạng khác. Khi tham chiếu một Mã nhận dạng tài nguyên Android, bạn không cần phải có biểu tượng dấu cộng, nhưng bạn phải thêm Không gian tên của gói android như sau:

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

Không gian tên gói android cho biết bạn đang tham chiếu một mã nhận dạng từ lớp tài nguyên android.R chứ không phải từ lớp tài nguyên.

Để tạo các khung hiển thị và tham chiếu đến các khung hiển thị đó từ ứng dụng của mình, bạn có thể sử dụng mẫu như sau:

  1. Xác định một thành phần hiển thị trong tệp bố cục và gán mã nhận dạng duy nhất cho thành phần hiển thị đó, như trong ví dụ sau:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
    
  2. Tạo một thực thể của đối tượng thành phần hiển thị và chụp đối tượng đó từ bố cục thường trong onCreate() như được thể hiện trong ví dụ sau:

    Kotlin

    val myButton: Button = findViewById(R.id.my_button)
    

    Java

    Button myButton = (Button) findViewById(R.id.my_button);
    

Việc xác định mã nhận dạng cho đối tượng khung hiển thị là rất quan trọng khi tạo RelativeLayout. Trong bố cục tương đối, các khung hiển thị đồng cấp có thể xác định bố cục so với một bố cục khác khung hiển thị đồng cấp được tham chiếu theo mã nhận dạng duy nhất.

Mã nhận dạng không nhất thiết phải là duy nhất trong toàn bộ cây, nhưng phải là duy nhất trong phần cây mà bạn tìm kiếm. Thường có thể là toàn bộ do đó tốt nhất nên tạo biểu trưng là duy nhất khi có thể.

Tham số bố cục

Thuộc tính bố cục XML có tên là layout_something xác định tham số bố cục cho View phù hợp với ViewGroup chứa phần này.

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í của mỗi loại khung hiển thị con, cho phù hợp với nhóm khung hiển thị. Như trong hình 2, phần tử mẹ nhóm khung hiển thị xác định các tham số bố cục cho mỗi khung hiển thị con, bao gồm cả khung hiển thị con nhóm chế độ xem.

Hình 2. Hình ảnh minh hoạ hệ phân cấp khung hiển thị có bố cục liên kết với mỗi chế độ xem.

Mỗi lớp con LayoutParams đều có cú pháp riêng để đặt chế độ cài đặt giá trị. Mỗi phần tử con phải xác định một LayoutParams phù hợp với cấp độ gốc, mặc dù mã này cũng có thể xác định một LayoutParams cho các phần tử con của chính nó.

Tất cả các nhóm chế độ xem đều có chiều rộng và chiều cao, sử dụng layout_widthlayout_height. Mỗi thành phần hiển thị bắt buộc phải xác định các thuộc tính này. Nhiều LayoutParams bao gồm lề và đường viền không bắt buộc.

Bạn có thể chỉ định chiều rộng và chiều cao bằng các số đo chính xác, nhưng có thể không muốn làm điều này thường xuyên. Thông thường, bạn sử dụng một trong các hằng số này để đặt giá trị chiều rộng hoặc chiều cao:

  • wrap_content: yêu cầu khung hiển thị tự định kích thước theo các kích thước cần thiết theo nội dung.
  • match_parent: yêu cầu thành phần hiển thị lớn bằng thành phần mẹ cho phép.

Nói chung, bạn không nên chỉ định chiều rộng và chiều cao bố cục bằng cách sử dụng đơn vị tuyệt đối như pixel. Một phương pháp hiệu quả hơn là sử dụng các phép đo tương đối, chẳng hạn như đơn vị pixel không phụ thuộc vào mật độ (dp), wrap_content hoặc match_parent vì thành phần này giúp ứng dụng của bạn hiển thị đúng cách trên nhiều kích thước màn hình thiết bị. Các loại đo lường được chấp nhận được xác định trong Tài nguyên bố cục.

Vị trí bố cục

Một khung hiển thị có hình chữ nhật. Nó có vị trí, được biểu thị dưới dạng một cặp toạ độ tráitrên cùng, cùng hai kích thước, được biểu thị bằng chiều rộng và chiều cao. Đơn vị của vị trí và kích thước là pixel.

Bạn có thể truy xuất vị trí của một khung hiển thị bằng cách gọi các phương thức getLeft()getTop() Phương thức thứ nhất trả về toạ độ bên trái (x) của hình chữ nhật biểu thị chế độ xem. Phương thức sau trả về toạ độ đỉnh (y) của hình chữ nhật biểu thị cho chế độ xem. Các phương thức này trả về vị trí của thành phần hiển thị so với thành phần mẹ của nó. Ví dụ: khi getLeft() trả về 20, điều này có nghĩa là chế độ xem trực tiếp nằm cách cạnh bên trái 20 pixel về phía bên phải cha mẹ.

Ngoài ra, còn có các phương thức thuận tiện để tránh các phép tính không cần thiết: cụ thể là getRight()getBottom() Các phương thức này trả về toạ độ của các cạnh bên phải và cạnh dưới của hình chữ nhật biểu thị khung hiển thị. Ví dụ: gọi getRight() là 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. Một thành phần hiển thị có 2 cặp gồm giá trị chiều rộng và chiều cao.

Cặp đầu tiên được gọi là chiều rộng đo đượcchiều cao đo được. Các kích thước này xác định kích thước mong muốn của một thành phần hiển thị trong phần tử mẹ. Bạn có thể lấy kích thước đã đo bằng cách gọi getMeasuredWidth()getMeasuredHeight()

Cặp thứ hai được gọi là chiều rộngchiều cao hoặc đôi khi chiều rộng bản vẽchiều cao bản vẽ. Các phương diện này xác định kích thước thực 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 bố cục. Các các giá trị có thể, nhưng không nhất thiết, khác với chiều rộng và chiều cao đo được. Bạn có thể lấy chiều rộng và chiều cao bằng cách gọi getWidth()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 chế độ xem. Bạn 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 cụ thể điểm ảnh. Ví dụ: khoảng đệm bên trái là 2 sẽ đẩy nội dung của khung hiển thị lên 2 pixel ở bên phải của cạnh trái. Bạn có thể đặt khoảng đệm bằng cách sử dụng setPadding(int, int, int, int) và truy vấn bằng cách gọi getPaddingLeft(), getPaddingTop(), getPaddingRight(), và getPaddingBottom().

Mặc dù thành phần hiển thị có thể xác định khoảng đệm, nhưng thành phần hiển thị này không hỗ trợ lề. Tuy nhiên, các nhóm khung hiển thị có hỗ trợ lề. Xem ViewGroupViewGroup.MarginLayoutParams để biết thêm thông tin.

Để biết thêm thông tin về phương diện, hãy xem Kích thước.

Ngoài việc đặt lề và khoảng đệm theo phương thức lập trình, bạn cũng có thể đặt chúng trong bố cục XML của bạn, như trong ví dụ sau:

  <?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:layout_margin="16dp"
                android:padding="8dp"
                android:text="Hello, I am a TextView" />
      <Button android:id="@+id/button"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="16dp"
              android:paddingBottom="4dp"
              android:paddingEnd="8dp"
              android:paddingStart="8dp"
              android:paddingTop="4dp"
              android:text="Hello, I am a Button" />
  </LinearLayout>
  

Ví dụ trước cho thấy lề và khoảng đệm đang được áp dụng. Chiến lược phát hành đĩa đơn TextView có lề và khoảng đệm đồng nhất được áp dụng xung quanh và Button sẽ hướng dẫn bạn cách áp dụng độc lập từng xu hướng cạnh.

Bố cục phổ biến

Mỗi lớp con của lớp ViewGroup cung cấp một cách riêng để hiển thị các chế độ xem mà bạn lồng vào đó. Loại bố cục linh hoạt nhất và cung cấp các công cụ tốt nhất để duy trì hệ phân cấp bố cục ở mức nông, là ConstraintLayout.

Sau đây là một số loại bố cục phổ biến được tích hợp vào Android chủ.

Tạo bố cục tuyến tính

Sắp xếp các phần tử con thành một hàng ngang hoặc dọc và 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.

Tạo ứng dụng web trong WebView

Hiển thị trang web.

Tạo danh sách động

Khi nội dung cho bố cục của bạn có tính động hoặc không được xác định trước, bạn có thể sử dụng RecyclerView hoặc một lớp con của AdapterView RecyclerView thường là lựa chọn tốt hơn vì nó sử dụng bộ nhớ hiệu quả hơn AdapterView.

Có thể dùng các bố cục phổ biến với RecyclerViewAdapterView bao gồm những lợi ích sau:

Danh sách

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

Lưới

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

RecyclerView mang đến nhiều khả năng hơn và lựa chọn để tạo một nhóm quảng cáo tuỳ chỉnh trình quản lý bố cục.

Điền dữ liệu vào thành phần hiển thị bộ chuyển đổi

Bạn có thể điền sẵn AdapterView chẳng hạn như ListView hoặc GridView bởi liên kết thực thể AdapterView với một Adapter, Lệnh này truy xuất dữ liệu 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 để truy xuất các loại dữ liệu khác nhau và tạo chế độ xem cho AdapterView Hai trình 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 khung hiển thị cho từng mục mảng bằng cách gọi toString() trên từng mục và đặt nội dung trong TextView.

Ví dụ: nếu bạn có một mảng chuỗi mà bạn muốn hiển thị trong một ListView, hãy khởi chạy một ArrayAdapter mới bằng cách sử dụng 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 như sau:

  • Ứng dụng của bạn Context
  • Bố cục chứa TextView cho mỗi chuỗi trong mảng
  • Mảng chuỗi

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

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 từng mục, bạn có thể ghi đè phương thức Phương thức toString() cho các đối tượng trong mảng của bạn. Hoặc để tạo một khung hiển thị cho mỗi mục không phải là TextView—ví dụ: nếu bạn muốn một ImageView cho mỗi mục mảng – mở rộng lớp ArrayAdapter và ghi đè getView() để trả về loại khung hiển thị bạn muốn cho mỗi 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ụng SimpleCursorAdapter, hãy chỉ định bố cục cần sử dụng cho mỗi hàng trong Cursor và cột nào trong Cursor bạn muốn chèn vào thành phần hiển thị của bố cục bạn muốn. Ví dụ: nếu bạn 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ác cột cho tên và số. Bạn sau đó tạo một mảng chuỗi chỉ định cột nào từ Cursor mà bạn muốn trong bố cục cho mỗi kết quả và một số nguyên chỉ định các thành phần hiển thị tương ứng mà mỗi cột cần đượ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 thực thể cho SimpleCursorAdapter, hãy truyền bố cục để sử dụng cho từng kết quả, Cursor chứa 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 chế độ xem cho từng hàng trong Cursor sử dụng bố cục được cung cấp bằng cách chèn mỗi fromColumns mục vào toViews tương ứng chế độ xem.

Nếu trong quá trình hoạt động của ứng dụng, bạn thay đổi dữ liệu cơ bản được bộ chuyển đổi của bạn đọc, hãy gọi notifyDataSetChanged(). Thao tác này sẽ thông báo cho khung hiển thị đính kèm rằng dữ liệu đã được thay đổi và dữ liệu sẽ được làm mới. .

Xử lý các sự kiện nhấp chuột

Bạn có thể phản hồi các sự kiện nhấp chuột trên mỗi mục trong AdapterView bằng cách triển khai 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

Xem cách bố cục được sử dụng trong Hoa hướng dương ứng dụng minh hoạ trên GitHub.