Thêm bản xem trước vào trình chọn tiện ích

Để cải thiện trải nghiệm của bộ chọn tiện ích trong ứng dụng, hãy cung cấp bản xem trước tiện ích được tạo trên thiết bị Android 15 trở lên, bản xem trước tiện ích được điều chỉnh theo tỷ lệ (bằng cách chỉ định previewLayout) cho thiết bị Android 12 đến Android 14 và previewImage cho các phiên bản cũ hơn.

Bản xem trước tiện ích được tạo cho phép bạn tạo bản xem trước linh động, được cá nhân hoá cho tiện ích của mình, phản ánh chính xác cách tiện ích sẽ xuất hiện trên màn hình chính của người dùng. Đối với Android 15 trở lên, các bản xem trước này được cung cấp thông qua một API đẩy, nghĩa là ứng dụng của bạn cung cấp bản xem trước tại bất kỳ thời điểm nào trong vòng đời mà không cần nhận yêu cầu rõ ràng từ máy chủ lưu trữ tiện ích.

Để biết thêm thông tin, hãy xem video Làm phong phú ứng dụng bằng thông tin cập nhật trực tiếp và tiện ích trên YouTube.

Thêm bản xem trước được tạo

Để hiển thị Bản xem trước tiện ích được tạo trên thiết bị Android 15 trở lên, trước tiên, hãy đặt giá trị compileSdk thành 35 trở lên trong tệp mô-đun build.gradle để có thể cung cấp RemoteViews cho bộ chọn tiện ích

Ứng dụng có thể sử dụng setWidgetPreview trong AppWidgetManager. Để ngăn chặn hành vi sai trái và giảm thiểu các vấn đề về tình trạng hệ thống, setWidgetPreview là một API có giới hạn tốc độ. Hạn mức mặc định là khoảng hai lệnh gọi mỗi giờ.

Hệ thống không có lệnh gọi lại để cung cấp bản xem trước, vì vậy, ứng dụng của bạn phải quyết định thời điểm gọi setWidgetPreviews. Chiến lược cập nhật phụ thuộc vào trường hợp sử dụng của tiện ích:

  • Nếu tiện ích có thông tin tĩnh hoặc là một thao tác nhanh, hãy đặt bản xem trước khi ứng dụng được chạy lần đầu.
  • Bạn có thể đặt bản xem trước sau khi ứng dụng có dữ liệu; ví dụ: sau khi người dùng đăng nhập hoặc thiết lập ban đầu.
  • Bạn có thể thiết lập một tác vụ định kỳ để cập nhật bản xem trước theo tần suất đã chọn.

Ví dụ sau đây tải tài nguyên bố cục tiện ích XML và đặt tài nguyên đó làm bản xem trước. Bạn cần có chế độ cài đặt bản dựng compileSdk từ 35 trở lên để setWidgetPreview xuất hiện dưới dạng một phương thức trong đoạn mã này.

AppWidgetManager.getInstance(appContext).setWidgetPreview(
    ComponentName(
        appContext,
        ExampleAppWidgetReceiver::class.java
    ),
    AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
    RemoteViews("com.example", R.layout.widget_preview)
)

Thêm bản xem trước tiện ích có thể mở rộng

Kể từ Android 12, bản xem trước tiện ích xuất hiện trong bộ chọn tiện ích có thể mở rộng. Bạn cung cấp bố cục này dưới dạng bố cục XML được đặt thành kích thước mặc định của tiện ích. Trước đây, bản xem trước tiện ích là một tài nguyên drawable tĩnh, trong một số trường hợp, bản xem trước này không phản ánh chính xác giao diện của tiện ích khi được thêm vào màn hình chính.

Để triển khai bản xem trước tiện ích có thể mở rộng, hãy sử dụng thuộc tính previewLayout của phần tử appwidget-provider để cung cấp bố cục XML:

<appwidget-provider
    android:previewLayout="@layout/my_widget_preview">
</appwidget-provider>

Bạn nên sử dụng cùng một bố cục với tiện ích thực tế, có giá trị mặc định hoặc giá trị kiểm thử thực tế. Hầu hết các ứng dụng đều sử dụng cùng một previewLayout và initialLayout. Để biết hướng dẫn về cách tạo bố cục xem trước chính xác, hãy xem bài viết Tạo bản xem trước chính xác có chứa các mục động.

Bạn nên chỉ định cả hai thuộc tính previewLayout và previewImage để ứng dụng có thể quay lại sử dụng previewImage nếu thiết bị của người dùng không hỗ trợ previewLayout. Thuộc tính previewLayout được ưu tiên hơn thuộc tính previewImage.

Thêm bản xem trước tiện ích tĩnh để có khả năng tương thích ngược

Để cho phép bộ chọn tiện ích trên Android 11 (cấp độ API 30) trở xuống hiển thị bản xem trước của tiện ích hoặc làm phương án dự phòng cho bản xem trước có thể mở rộng, hãy chỉ định thuộc tính previewImage.

Nếu bạn thay đổi giao diện của tiện ích, hãy cập nhật hình ảnh xem trước.

Thuộc tính này cũng được dùng làm phương án dự phòng cho các bản xem trước được tạo nếu bạn chưa đặt một bản xem trước bằng setWidgetPreview.

Tạo bản xem trước chính xác, bao gồm cả các mục động

Hình 1: Bản xem trước tiện ích không hiển thị mục danh sách nào.

Phần này giải thích phương pháp đề xuất để hiển thị nhiều mục trong bản xem trước tiện ích cho một tiện ích có chế độ xem tập hợp, tức là một tiện ích sử dụng ListView, GridView hoặc StackView. Điều này áp dụng cho bản xem trước tiện ích có thể mở rộng, chứ không phải bản xem trước được tạo.

Nếu tiện ích của bạn sử dụng một trong các thành phần hiển thị này, thì việc tạo bản xem trước có thể mở rộng bằng cách cung cấp trực tiếp bố cục tiện ích thực tế trong previewLayout có thể làm giảm trải nghiệm khi bản xem trước tiện ích không hiển thị mục nào. Điều này xảy ra vì dữ liệu thành phần hiển thị tập hợp được đặt linh động trong thời gian chạy và trông giống như hình ảnh trong hình 1.

Để bản xem trước của các tiện ích có chế độ xem tập hợp hiển thị đúng cách trong bộ chọn tiện ích, bạn nên duy trì một tệp bố cục riêng chỉ dành cho bản xem trước. Tệp bố cục riêng biệt này phải bao gồm những nội dung sau:

  • Bố cục thực tế của tiện ích.
  • Khung hiển thị bộ sưu tập phần giữ chỗ có các mục giả. Ví dụ: bạn có thể bắt chước một ListView bằng cách cung cấp một phần giữ chỗ LinearLayout với một số mục danh sách giả.

Để minh hoạ một ví dụ về ListView, hãy bắt đầu bằng một tệp bố cục riêng:

// res/layout/widget_preview.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="@drawable/widget_background"
   android:orientation="vertical">

    // Include the actual widget layout that contains ListView.
    <include
        layout="@layout/widget_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    // The number of fake items you include depends on the values you provide
    // for minHeight or targetCellHeight in the AppWidgetProviderInfo
    // definition.

    <TextView android:text="@string/fake_item1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginVertical="?attr/appWidgetInternalPadding" />

    <TextView android:text="@string/fake_item2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginVertical="?attr/appWidgetInternalPadding" />

</LinearLayout>

Chỉ định tệp bố cục xem trước khi cung cấp thuộc tính previewLayout của siêu dữ liệu AppWidgetProviderInfo. Bạn vẫn chỉ định bố cục tiện ích thực tế cho thuộc tính initialLayout và sử dụng bố cục tiện ích thực tế khi tạo RemoteViews trong thời gian chạy.

<appwidget-provider
    previewLayout="@layout/widget_preview"
    initialLayout="@layout/widget_view" />

Mục danh sách phức tạp

Ví dụ trong phần trước cung cấp các mục danh sách giả, vì các mục danh sách là đối tượng TextView. Việc cung cấp các mục giả có thể phức tạp hơn nếu các mục đó là bố cục phức tạp.

Hãy xem xét một mục danh sách được xác định trong widget_list_item.xml và bao gồm hai đối tượng TextView:

<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <TextView android:id="@id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/fake_title" />

    <TextView android:id="@id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/fake_content" />
</LinearLayout>

Để cung cấp các mục danh sách giả, bạn có thể đưa bố cục vào nhiều lần, nhưng điều này khiến mỗi mục danh sách đều giống hệt nhau. Để cung cấp các mục danh sách riêng biệt, hãy làm theo các bước sau:

  1. Tạo một tập hợp thuộc tính cho các giá trị văn bản:

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. Sử dụng các thuộc tính sau để đặt văn bản:

    <LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
        <TextView android:id="@id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="?widgetTitle" />
    
        <TextView android:id="@id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="?widgetContent" />
    </LinearLayout>
    
  3. Tạo bao nhiêu kiểu tuỳ ý cho bản xem trước. Xác định lại các giá trị trong mỗi kiểu:

    <resources>
    
        <style name="Theme.Widget.ListItem">
            <item name="widgetTitle"></item>
            <item name="widgetContent"></item>
        </style>
        <style name="Theme.Widget.ListItem.Preview1">
            <item name="widgetTitle">Fake Title 1</item>
            <item name="widgetContent">Fake content 1</item>
        </style>
        <style name="Theme.Widget.ListItem.Preview2">
            <item name="widgetTitle">Fake title 2</item>
            <item name="widgetContent">Fake content 2</item>
        </style>
    
    </resources>
    
  4. Áp dụng kiểu cho các mục giả trong bố cục xem trước:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" ...>
    
        <include layout="@layout/widget_view" ... />
    
        <include layout="@layout/widget_list_item"
            android:theme="@style/Theme.Widget.ListItem.Preview1" />
    
        <include layout="@layout/widget_list_item"
            android:theme="@style/Theme.Widget.ListItem.Preview2" />
    
    </LinearLayout>