Thiết kế thích ứng/đáp ứng bằng khung hiển thị

Bố cục thích ứng cung cấp trải nghiệm người dùng được tối ưu hoá bất kể kích thước màn hình. Triển khai bố cục thích ứng để cho phép ứng dụng dựa trên khung hiển thị hỗ trợ tất cả các kích thước, hướng và cấu hình hiển thị, bao gồm cả các cấu hình có thể đổi kích thước như chế độ nhiều cửa sổ.

Thiết kế đáp ứng

Bước đầu tiên để hỗ trợ nhiều kiểu dáng thiết bị là tạo một bố cục thích ứng với các biến thể về lượng không gian hiển thị có sẵn cho ứng dụng.

ConstraintLayout

Cách tốt nhất để tạo bố cục thích ứng là sử dụng ConstraintLayout làm bố cục cơ sở cho giao diện người dùng. ConstraintLayout cho phép bạn chỉ định vị trí và kích thước của mỗi thành phần hiển thị theo mối quan hệ không gian với các thành phần hiển thị khác trong bố cục. Sau đó, tất cả thành phần hiển thị có thể di chuyển và đổi kích thước cùng nhau khi không gian hiển thị thay đổi.

Cách dễ nhất để tạo bố cục với ConstraintLayout là sử dụng Layout Editor (Trình chỉnh sửa bố cục) trong Android Studio. Layout Editor cho phép bạn kéo các khung hiển thị mới vào bố cục, áp dụng các quy tắc ràng buộc liên quan đến khung hiển thị mẹ và khung hiển thị đồng cấp, đồng thời đặt thuộc tính khung hiển thị mà không cần chỉnh sửa XML theo cách thủ công.

Hình 3. Layout Editor (Trình chỉnh sửa bố cục) trong Android Studio cho thấy ConstraintLayout.

Để biết thêm thông tin, hãy xem nội dung Tạo giao diện người dùng thích ứng bằng ConstraintLayout.

Chiều rộng và chiều cao đáp ứng

Để đảm bảo bố cục thích ứng với nhiều kích thước màn hình, hãy sử dụng wrap_content, match_parent hoặc 0dp (match constraint) cho chiều rộng và chiều cao của các thành phần khung hiển thị thay vì các giá trị được cố định giá trị trong mã:

  • wrap_content: Khung hiển thị đặt kích thước phù hợp với nội dung trong khung hiển thị đó.
  • match_parent: Thành phần hiển thị này mở rộng nhiều nhất có thể trong thành phần hiển thị mẹ.
  • 0dp (match constraint): Trong ConstraintLayout, tương tự như match_parent. Khung hiển thị này nhận tất cả không gian có sẵn trong các quy tắc ràng buộc của khung hiển thị đó.

Ví dụ:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/lorem_ipsum" />

Hình 4 cho thấy cách chiều rộng và chiều cao của TextView điều chỉnh khi chiều rộng màn hình thay đổi theo hướng thiết bị.

Hình 4. TextView thích ứng.

TextView đặt chiều rộng để lấp đầy tất cả không gian có sẵn (match_parent) và chiều cao của nó chính xác bằng không gian cần thiết theo chiều cao của văn bản chứa (wrap_content), giúp thành phần hiển thị thích ứng với nhiều kích thước hiển thị và lượng văn bản khác nhau.

Nếu đang sử dụng LinearLayout, bạn cũng có thể mở rộng các thành phần hiển thị con dựa trên trọng số bố cục để các thành phần hiển thị này lấp đầy tỷ lệ không gian có sẵn. Tuy nhiên, việc sử dụng các trọng số trong LinearLayout lồng nhau yêu cầu hệ thống phải thực hiện nhiều lần truyền bố cục để xác định kích thước cho mỗi khung hiển thị, từ đó làm chậm hiệu suất của giao diện người dùng.

ConstraintLayout có thể tạo gần như tất cả bố cục có thể có bằng LinearLayout mà không ảnh hưởng đến hiệu suất, vì vậy, hãy chuyển đổi LinearLayout lồng nhau thành ConstraintLayout. Sau đó, bạn có thể xác định bố cục có trọng số bằng chuỗi ràng buộc.

Thiết kế thích ứng

Bố cục của ứng dụng phải luôn thích ứng với nhiều kích thước màn hình. Tuy nhiên, ngay cả bố cục thích ứng cũng không thể cung cấp trải nghiệm người dùng tốt nhất trên mọi thiết bị hoặc màn hình ở chế độ nhiều cửa sổ. Ví dụ: giao diện người dùng mà bạn thiết kế cho điện thoại có thể chưa cung cấp trải nghiệm người dùng tối ưu trên máy tính bảng. Thiết kế thích ứng cung cấp các bố cục thay thế được tối ưu hoá cho nhiều kích thước màn hình.

SlidingPaneLayout cho các giao diện người dùng dạng danh sách-chi tiết

Giao diện người dùng chi tiết về danh sách thường cung cấp trải nghiệm người dùng khác trên các màn hình có kích thước khác nhau. Trên màn hình lớn, danh sách và ngăn chi tiết thường nằm cạnh nhau. Khi một mục trong danh sách được chọn, thông tin về mục đó sẽ xuất hiện trong ngăn chi tiết mà không làm thay đổi giao diện người dùng. Hai ngăn vẫn nằm cạnh nhau. Tuy nhiên, trên các màn hình nhỏ, 2 ngăn được hiển thị riêng biệt, mỗi ngăn chiếm toàn bộ khu vực hiển thị. Khi một mục trong ngăn danh sách được chọn, ngăn chi tiết (chứa thông tin của mục đã chọn) sẽ thay thế ngăn danh sách. Thao tác quay lại sẽ thay thế ngăn chi tiết bằng danh sách.

SlidingPaneLayout quản lý logic để xác định trải nghiệm người dùng trong hai trải nghiệm người dùng phù hợp với kích thước cửa sổ hiện tại:

<?xml version="1.0" encoding="utf-8"?>
<androidx.slidingpanelayout.widget.SlidingPaneLayout
    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=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/item_navigation" />

</androidx.slidingpanelayout.widget.SlidingPaneLayout>

Thuộc tính layout_widthlayout_weight của hai thành phần hiển thị có trong SlidingPaneLayout xác định hành vi của SlidingPaneLayout. Trong ví dụ, nếu cửa sổ đủ lớn (chiều rộng tối thiểu là 580 dp) để hiển thị cả hai khung hiển thị, thì các ngăn sẽ hiển thị cạnh nhau. Tuy nhiên, nếu chiều rộng cửa sổ nhỏ hơn 580dp, các ngăn sẽ trượt qua nhau để chiếm toàn bộ cửa sổ ứng dụng.

Nếu chiều rộng cửa sổ lớn hơn tổng chiều rộng tối thiểu đã chỉ định (580 dp), thì bạn có thể dùng các giá trị layout_weight để xác định kích thước hai ngăn theo tỷ lệ. Trong ví dụ, ngăn danh sách luôn rộng 280 dp vì không có trọng số. Tuy nhiên, ngăn chi tiết luôn lấp đầy bất kỳ không gian ngang nào vượt quá 580 dp do chế độ cài đặt layout_weight của chế độ xem.

Tài nguyên bố cục thay thế

Để điều chỉnh thiết kế giao diện người dùng của bạn cho phù hợp với nhiều kích thước màn hình, hãy sử dụng bố cục thay thế được xác định bằng bộ hạn định tài nguyên.

Hình 5. Cùng một ứng dụng sử dụng nhiều bố cục cho nhiều kích thước màn hình.

Bạn có thể cung cấp bố cục thích ứng, dành riêng cho màn hình bằng cách tạo thêm thư mục res/layout/ trong mã nguồn của ứng dụng. Tạo thư mục cho từng cấu hình màn hình yêu cầu bố cục khác nhau. Sau đó, hãy thêm một bộ hạn định cấu hình màn hình vào tên thư mục layout (ví dụ: layout-w600dp cho các màn hình có chiều rộng có sẵn là 600 dp).

Chuỗi định tính cấu hình đại diện cho không gian hiển thị hiển thị có sẵn cho giao diện người dùng ứng dụng. Hệ thống xem xét mọi trang trí hệ thống (chẳng hạn như thanh điều hướng) và các thay đổi về cấu hình cửa sổ (chẳng hạn như chế độ nhiều cửa sổ) khi chọn bố cục cho ứng dụng.

Để tạo bố cục thay thế trong Android Studio, hãy xem phần Sử dụng biến thể bố cục để tối ưu hoá cho nhiều màn hình trong bài viết Phát triển giao diện người dùng bằng Khung hiển thị.

Bộ hạn định có chiều rộng nhỏ nhất

Bộ hạn định kích thước màn hình chiều rộng nhỏ nhất cho phép bạn cung cấp bố cục thay thế cho các màn hình có chiều rộng tối thiểu được đo bằng pixel không phụ thuộc vào mật độ (dp).

Bằng cách mô tả kích thước màn hình là số đo dp, Android cho phép bạn tạo bố cục được thiết kế cho các kích thước hiển thị cụ thể mà không cần quan tâm đến mật độ pixel khác nhau.

Ví dụ: bạn có thể tạo một bố cục có tên là main_activity được tối ưu hoá cho điện thoại và máy tính bảng bằng cách tạo nhiều phiên bản của tệp trong nhiều thư mục:

res/layout/main_activity.xml           # For phones (smaller than 600dp smallest width)
res/layout-sw600dp/main_activity.xml   # For 7" tablets (600dp wide or wider)

Bộ hạn định chiều rộng nhỏ nhất chỉ định kích thước nhỏ nhất trong số hai cạnh của màn hình, bất kể hướng hiện tại của thiết bị là gì. Vì vậy, đây là một cách để chỉ định kích thước tổng thể có sẵn cho bố cục của bạn.

Dưới đây là cách các giá trị chiều rộng nhỏ nhất tương ứng với kích thước màn hình thông thường:

  • 320dp: Màn hình điện thoại nhỏ (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, v.v.)
  • 480dp: Màn hình điện thoại lớn ~5 inch (480x800 mdpi).
  • 600dp: Máy tính bảng 7 inch (600x1024 mdpi)
  • 720dp: Máy tính bảng 10 inch (720x1280 mdpi, 800x1280 mdpi, v.v.)

Hình sau đây cung cấp thông tin chi tiết hơn về độ rộng (dp) của màn hình tương ứng với các kích thước và hướng màn hình khác nhau.

Hình 6. Điểm chuyển đổi chiều rộng đề xuất để hỗ trợ các kích thước màn hình khác nhau.

Giá trị cho bộ hạn định chiều rộng nhỏ nhất là dp, vì điều quan trọng là lượng không gian hiển thị có sẵn sau khi hệ thống tính mật độ pixel (không phải độ phân giải pixel thô).

Kích thước bạn chỉ định bằng cách sử dụng bộ hạn định tài nguyên như chiều rộng nhỏ nhất không phải là kích thước màn hình thực tế. Thay vào đó, kích thước chỉ định chiều rộng hoặc chiều cao tính bằng đơn vị dp có trong cửa sổ ứng dụng. Hệ thống Android có thể sử dụng một số màn hình cho giao diện người dùng hệ thống (chẳng hạn như thanh hệ thống ở cuối màn hình hoặc thanh trạng thái ở trên cùng), vì vậy, một số màn hình có thể không đáp ứng được bố cục của bạn. Nếu bạn dùng ứng dụng ở chế độ nhiều cửa sổ, thì ứng dụng chỉ có quyền truy cập vào kích thước của cửa sổ chứa ứng dụng đó. Khi cửa sổ được đổi kích thước, cửa sổ sẽ kích hoạt quá trình thay đổi cấu hình theo kích thước cửa sổ mới để cho phép hệ thống chọn tệp bố cục phù hợp. Vì vậy, kích thước bộ hạn định tài nguyên bạn khai báo chỉ nên chỉ định không gian cần thiết cho ứng dụng của bạn. Hệ thống có tính đến mọi không gian mà giao diện người dùng hệ thống sử dụng khi cung cấp không gian cho bố cục.

Bộ hạn định chiều rộng có sẵn

Thay vì thay đổi bố cục dựa trên chiều rộng nhỏ nhất của màn hình, bạn có thể thay đổi bố cục dựa trên chiều rộng hoặc chiều cao hiện có. Ví dụ: bạn có thể sử dụng bố cục 2 ngăn bất cứ khi nào màn hình cung cấp chiều rộng tối thiểu là 600 dp. Kích thước này có thể thay đổi tuỳ thuộc vào việc thiết bị ở hướng ngang hay dọc. Trong trường hợp đó, bạn nên sử dụng bộ hạn định chiều rộng có sẵn như sau:

res/layout/main_activity.xml         # For phones (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # For 7" tablets or any screen with 600dp available width
                                     # (possibly landscape phones)

Nếu lo ngại về chiều cao có sẵn cho ứng dụng của mình, bạn có thể sử dụng bộ hạn định chiều cao hiện có. Ví dụ: layout-h600dp cho màn hình có chiều cao tối thiểu là 600 dp.

Bộ hạn định hướng

Mặc dù bạn có thể hỗ trợ tất cả các biến thể kích thước chỉ bằng cách sử dụng tổ hợp bộ hạn định chiều rộng nhỏ nhấtchiều rộng có sẵn, nhưng bạn cũng nên thay đổi trải nghiệm người dùng khi người dùng chuyển đổi giữa hướng dọc và ngang.

Để làm được việc đó, bạn có thể thêm bộ hạn định port hoặc land vào tên thư mục bố cục. Chỉ cần đảm bảo bộ hạn định hướng xuất hiện sau bộ hạn định kích thước. Ví dụ:

res/layout/main_activity.xml                # For phones
res/layout-land/main_activity.xml           # For phones in landscape
res/layout-sw600dp/main_activity.xml        # For 7" tablets
res/layout-sw600dp-land/main_activity.xml   # For 7" tablets in landscape

Để biết thêm thông tin về tất cả các bộ hạn định cấu hình màn hình, hãy xem nội dung Tổng quan về tài nguyên ứng dụng.

Các lớp kích thước cửa sổ

Các lớp kích thước cửa sổ là các điểm ngắt khung nhìn giúp bạn tạo bố cục thích ứng. Các điểm ngắt xác định khu vực hiển thị có sẵn cho ứng dụng của bạn là nhỏ gọn, trung bình hoặc mở rộng. Chiều rộng và chiều cao được chỉ định riêng biệt, vì vậy, ứng dụng của bạn luôn có một lớp kích thước cửa sổ cho chiều rộng và một lớp kích thước cửa sổ cho chiều cao.

Để áp dụng bố cục thích ứng theo phương thức lập trình, hãy làm như sau:

  • Tạo tài nguyên bố cục dựa trên các điểm ngắt lớp kích thước cửa sổ
  • Tính toán các lớp kích thước cửa sổ chiều rộng và chiều cao của ứng dụng bằng cách sử dụng hàm WindowSizeClass#compute() từ thư viện Jetpack WindowManager
  • Tăng cường tài nguyên bố cục cho các lớp kích thước cửa sổ hiện tại

Để biết thêm thông tin về các lớp kích thước cửa sổ, hãy xem bài viết Hỗ trợ nhiều kích thước màn hình.

Thành phần giao diện người dùng được mô-đun hóa sử dụng mảnh

Khi thiết kế ứng dụng cho nhiều kích thước màn hình, hãy sử dụng các mảnh để trích xuất logic giao diện người dùng thành các thành phần riêng biệt để đảm bảo bạn không cần lặp lại hành vi giao diện người dùng trên các hoạt động. Sau đó, bạn có thể kết hợp các mảnh để tạo bố cục nhiều ngăn trên màn hình lớn hoặc bạn có thể đặt các mảnh trong các hoạt động riêng biệt trên màn hình nhỏ.

Ví dụ: mẫu danh sách-chi tiết (xem SlidingPaneLayout ở trên) có thể được triển khai với một mảnh chứa danh sách và một mảnh khác chứa chi tiết mục danh sách. Trên màn hình lớn, các mảnh có thể hiển thị cạnh nhau; trên các màn hình nhỏ, riêng lẻ, lấp đầy màn hình.

Để tìm hiểu thêm, hãy xem thông tin tổng quan về Mảnh.

Nhúng hoạt động

Nếu ứng dụng bao gồm nhiều hoạt động, tính năng nhúng hoạt động sẽ cho phép bạn dễ dàng tạo giao diện người dùng thích ứng.

Tính năng nhúng hoạt động hiển thị đồng thời nhiều hoạt động hoặc nhiều phiên bản của cùng một hoạt động trong cửa sổ tác vụ của ứng dụng. Trên màn hình lớn, các hoạt động có thể hiển thị cạnh nhau; trên màn hình nhỏ, xếp chồng lên nhau.

Bạn xác định cách ứng dụng hiển thị hoạt động của mình bằng cách tạo tệp cấu hình XML mà hệ thống dùng để xác định bản trình bày phù hợp dựa trên kích thước hiển thị. Ngoài ra, bạn có thể thực hiện các lệnh gọi API Jetpack WindowManager.

Tính năng nhúng hoạt động hỗ trợ các thay đổi về hướng thiết bị và thiết bị có thể gập lại, xếp các hoạt động vào nhóm và huỷ xếp các hoạt động khi thiết bị xoay, gập và mở ra.

Để biết thêm thông tin, hãy xem bài viết Nhúng hoạt động.

Kích thước màn hình và tỷ lệ khung hình

Kiểm thử ứng dụng trên nhiều kích thước màn hình và tỷ lệ khung hình để đảm bảo giao diện người dùng điều chỉnh tỷ lệ một cách chính xác.

Android 10 (API cấp 29) trở lên hỗ trợ nhiều tỷ lệ khung hình. Các kiểu dáng thiết bị có thể gập lại có thể khác nhau, từ màn hình cao và hẹp (chẳng hạn như 21:9 khi gập) đến tỷ lệ khung hình vuông 1:1 khi mở ra.

Để đảm bảo khả năng tương thích với nhiều thiết bị nhất có thể, hãy kiểm thử ứng dụng của bạn ở càng nhiều tỷ lệ khung hình sau đây càng tốt:

Hình 7. Nhiều tỷ lệ khung hình của màn hình.

Nếu không có quyền truy cập vào thiết bị cho mọi kích thước màn hình mà bạn muốn kiểm thử, bạn có thể sử dụng Trình mô phỏng Android để mô phỏng hầu hết mọi kích thước màn hình.

Nếu muốn kiểm thử trên một thiết bị thực tế nhưng không có thiết bị, bạn có thể sử dụng Phòng thử nghiệm Firebase để truy cập vào các thiết bị trong trung tâm dữ liệu của Google.

Tài nguyên khác