Trang này mô tả các điểm tinh chỉnh về việc định cỡ tiện ích và tính linh hoạt cao hơn được giới thiệu trong Android 12 (API cấp 31). Bài viết này cũng trình bày chi tiết cách xác định kích thước cho tiện ích của bạn.
Dùng API cải tiến đối với kích thước và bố cục tiện ích
Kể từ Android 12 (API cấp 31), bạn có thể cung cấp thêm kích thước đã tinh chỉnh và bố cục linh hoạt bằng cách làm như sau, như mô tả trong tiếp theo:
Cung cấp bố cục thích ứng hoặc bố cục chính xác.
Trong các phiên bản Android trước đây, bạn có thể lấy phạm vi kích thước của
bằng cách sử dụng
OPTION_APPWIDGET_MIN_WIDTH
!
OPTION_APPWIDGET_MIN_HEIGHT
!
OPTION_APPWIDGET_MAX_WIDTH
!
và OPTION_APPWIDGET_MAX_HEIGHT
dữ liệu bổ sung rồi ước tính kích thước tiện ích, nhưng logic đó không hoạt động trong tất cả các trường hợp
ngoại lệ. Đối với các tiện ích nhắm mục tiêu đến Android 12 trở lên, bạn nên
cung cấp đáp ứng hoặc chính xác
bố cục.
Chỉ định các quy tắc ràng buộc khác về kích thước tiện ích
Android 12 bổ sung các API giúp bạn đảm bảo kích thước tiện ích của mình được điều chỉnh một cách đáng tin cậy hơn trên nhiều thiết bị có kích thước màn hình khác nhau.
Ngoài các thuộc tính minWidth
, minHeight
, minResizeWidth
và minResizeHeight
hiện có, hãy sử dụng các thuộc tính appwidget-provider
mới sau:
targetCellWidth
vàtargetCellHeight
: xác định kích thước mục tiêu của tiện ích theo các ô lưới của trình chạy. Nếu được xác định, các thuộc tính này sẽ được sử dụng thay vìminWidth
hoặcminHeight
.maxResizeWidth
vàmaxResizeHeight
: xác định kích thước tối đa mà trình chạy cho phép người dùng đổi kích thước tiện ích.
XML sau đây cho biết cách sử dụng các thuộc tính kích thước.
<appwidget-provider
...
android:targetCellWidth="3"
android:targetCellHeight="2"
android:maxResizeWidth="250dp"
android:maxResizeHeight="110dp">
</appwidget-provider>
Cung cấp bố cục thích ứng
Nếu bố cục cần thay đổi tuỳ thuộc vào kích thước của tiện ích, bạn nên tạo một tập hợp nhỏ các bố cục, mỗi bố cục hợp lệ cho nhiều kích thước. Nếu không thể làm được điều này, bạn có thể cung cấp bố cục dựa trên kích thước tiện ích chính xác trong thời gian chạy, như mô tả trong trang này.
Tính năng này giúp mở rộng quy mô mượt mà hơn và cải thiện hệ thống tổng thể sức khoẻ, vì hệ thống không phải đánh thức ứng dụng mỗi lần nó sẽ hiển thị tiện ích đó ở một kích thước khác.
Ví dụ về mã sau đây cho thấy cách cung cấp danh sách bố cục.
Kotlin
override fun onUpdate(...) { val smallView = ... val tallView = ... val wideView = ... val viewMapping: Map<SizeF, RemoteViews> = mapOf( SizeF(150f, 100f) to smallView, SizeF(150f, 200f) to tallView, SizeF(215f, 100f) to wideView ) val remoteViews = RemoteViews(viewMapping) appWidgetManager.updateAppWidget(id, remoteViews) }
Java
@Override public void onUpdate(...) { RemoteViews smallView = ...; RemoteViews tallView = ...; RemoteViews wideView = ...; Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); viewMapping.put(new SizeF(150f, 100f), smallView); viewMapping.put(new SizeF(150f, 200f), tallView); viewMapping.put(new SizeF(215f, 100f), wideView); RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews); }
Giả sử tiện ích có các thuộc tính sau:
<appwidget-provider
android:minResizeWidth="160dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="250dp"
android:maxResizeHeight="200dp">
</appwidget-provider>
Đoạn mã trước có nghĩa như sau:
smallView
hỗ trợ từ 160 dp (minResizeWidth
) × 110 dp (minResizeHeight
) thành 160 dp × 199 dp (điểm cắt tiếp theo – 1 dp).tallView
hỗ trợ từ 160 dp × 200 dp đến 214 dp (điểm ngắt tiếp theo – 1) × 200 dp.wideView
hỗ trợ từ 215 dp x 110 dp (minResizeHeight
) đến 250 dp (maxResizeWidth
) x 200 dp (maxResizeHeight
).
Tiện ích của bạn phải hỗ trợ kích thước trong khoảng từ minResizeWidth
×
minResizeHeight
đến maxResizeWidth
× maxResizeHeight
. Trong phạm vi đó, bạn có thể quyết định điểm ngắt để chuyển đổi bố cục.
Cung cấp bố cục chính xác
Nếu không thể sử dụng một nhóm nhỏ bố cục thích ứng, bạn có thể cung cấp nhiều bố cục khác nhau phù hợp với kích thước hiển thị tiện ích. Đây là thường có 2 kích thước cho điện thoại (chế độ dọc và ngang) và 4 kích thước cho thiết bị có thể gập lại.
Để triển khai giải pháp này, ứng dụng của bạn cần thực hiện các bước sau:
Quá tải
AppWidgetProvider.onAppWidgetOptionsChanged()
, được gọi khi tập hợp kích thước thay đổi.Gọi
AppWidgetManager.getAppWidgetOptions()
để trả về mộtBundle
chứa các kích thước.Truy cập vào khoá
AppWidgetManager.OPTION_APPWIDGET_SIZES
trênBundle
.
Ví dụ về mã sau đây cho thấy cách cung cấp bố cục chính xác.
Kotlin
override fun onAppWidgetOptionsChanged( context: Context, appWidgetManager: AppWidgetManager, id: Int, newOptions: Bundle? ) { super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions) // Get the new sizes. val sizes = newOptions?.getParcelableArrayList<SizeF>( AppWidgetManager.OPTION_APPWIDGET_SIZES ) // Check that the list of sizes is provided by the launcher. if (sizes.isNullOrEmpty()) { return } // Map the sizes to the RemoteViews that you want. val remoteViews = RemoteViews(sizes.associateWith(::createRemoteViews)) appWidgetManager.updateAppWidget(id, remoteViews) } // Create the RemoteViews for the given size. private fun createRemoteViews(size: SizeF): RemoteViews { }
Java
@Override public void onAppWidgetOptionsChanged( Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); // Get the new sizes. ArrayList<SizeF> sizes = newOptions.getParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES); // Check that the list of sizes is provided by the launcher. if (sizes == null || sizes.isEmpty()) { return; } // Map the sizes to the RemoteViews that you want. Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); for (SizeF size : sizes) { viewMapping.put(size, createRemoteViews(size)); } RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews); } // Create the RemoteViews for the given size. private RemoteViews createRemoteViews(SizeF size) { }
Xác định kích thước cho tiện ích của bạn
Mỗi tiện ích phải xác định một targetCellWidth
và targetCellHeight
cho các thiết bị
chạy Android 12 trở lên — hoặc minWidth
và minHeight
cho tất cả thiết bị
phiên bản Android—cho biết mức dung lượng tối thiểu mà ứng dụng đã sử dụng
theo mặc định. Tuy nhiên, khi người dùng thêm một tiện ích vào màn hình chính, việc này thường
chiếm nhiều hơn chiều rộng và chiều cao tối thiểu mà bạn chỉ định.
Màn hình chính Android cung cấp cho người dùng một lưới các không gian có sẵn để họ có thể đặt tiện ích và biểu tượng. Lưới này có thể khác nhau tuỳ theo thiết bị; ví dụ: nhiều điện thoại di động cung cấp lưới 5x4 và máy tính bảng có thể cung cấp lưới lớn hơn. Khi được thêm, tiện ích sẽ được kéo giãn để chiếm số lượng ô tối thiểu theo chiều ngang và chiều dọc cần thiết để đáp ứng các quy tắc ràng buộc cho targetCellWidth
và targetCellHeight
trên các thiết bị chạy Android 12 trở lên, hoặc các quy tắc ràng buộc minWidth
và minHeight
trên các thiết bị chạy Android 11 (API cấp 30) trở xuống.
Cả chiều rộng và chiều cao của một ô cũng như kích thước của lề tự động áp dụng cho các tiện ích có thể khác nhau giữa các thiết bị. Sử dụng bảng sau để ước tính ước tính kích thước tối thiểu của tiện ích của bạn trong điện thoại di động có lưới 5x4 thông thường, dựa trên số lượng ô lưới bị chiếm dụng mà bạn muốn:
Số ô (chiều rộng x chiều cao) | Kích thước có sẵn ở chế độ dọc (dp) | Kích thước có sẵn ở chế độ ngang (dp) |
---|---|---|
1x1 | 57x102 dp | 127x51dp |
2x1 | 130x102dp | 269x51 dp |
3x1 | 203x102 dp | 412x51 dp |
4x1 | 276x102dp | 554x51dp |
5x1 | 349x102 dp | 697x51dp |
5x2 | 349x220dp | 697x117 dp |
5x3 | 349x337 dp | 697x184dp |
5x4 | 349x455dp | 697x250 dp |
... | ... | ... |
n x m | (73n – 16) x (118m – 16) | (142n – 15) x (66m – 15) |
Sử dụng kích thước ô ở chế độ chân dung để cung cấp thông tin về các giá trị mà bạn cung cấp cho thuộc tính minWidth
, minResizeWidth
và maxResizeWidth
. Tương tự,
sử dụng kích thước ô ở chế độ ngang để cho biết các giá trị mà bạn cung cấp
cho các thuộc tính minHeight
, minResizeHeight
và maxResizeHeight
.
Lý do là chiều rộng của ô thường nhỏ hơn ở chế độ dọc so với chế độ ngang. Tương tự, chiều cao của ô thường nhỏ hơn ở chế độ ngang so với chế độ dọc.
Ví dụ: Nếu bạn muốn chiều rộng tiện ích có thể đổi kích thước thành một ô trên
Google Pixel 4, bạn cần đặt minResizeWidth
thành tối đa 56 dp
để đảm bảo giá trị của thuộc tính minResizeWidth
nhỏ hơn
lớn hơn 57 dp – vì ô có chiều dọc ít nhất là 57 dp.
Tương tự, nếu bạn muốn chiều cao của tiện ích có thể đổi kích thước trong một ô trên
cùng một thiết bị, bạn cần đặt minResizeHeight
ở mức tối đa là 50dp để đảm bảo
giá trị của thuộc tính minResizeHeight
nhỏ hơn
51 dp – vì một ô có chiều cao tối thiểu là 51 dp ở chế độ ngang.
Bạn có thể đổi kích thước của mỗi tiện ích trong phạm vi kích thước giữa các thuộc tính minResizeWidth
/minResizeHeight
và maxResizeWidth
/maxResizeHeight
, tức là tiện ích cần thích ứng với mọi phạm vi kích thước giữa các thuộc tính này.
Ví dụ: để đặt kích thước mặc định của tiện ích tại vị trí, bạn có thể thiết lập các thuộc tính sau:
<appwidget-provider
android:targetCellWidth="3"
android:targetCellHeight="2"
android:minWidth="180dp"
android:minHeight="110dp">
</appwidget-provider>
Điều này có nghĩa là kích thước mặc định của tiện ích là 3x2 ô, như được chỉ định bởi
Các thuộc tính targetCellWidth
và targetCellHeight
(hoặc 180×110 dp)
do minWidth
và minHeight
chỉ định cho các thiết bị đang chạy
Android 11 trở xuống. Trong trường hợp sau, kích thước trong các ô có thể
khác nhau tuỳ theo thiết bị.
Ngoài ra, để đặt phạm vi kích thước được hỗ trợ của tiện ích, bạn có thể đặt các thuộc tính sau:
<appwidget-provider
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="530dp"
android:maxResizeHeight="450dp">
</appwidget-provider>
Như đã chỉ định theo các thuộc tính trước, chiều rộng của tiện ích có thể thay đổi kích thước từ 180 dp đến 530 dp và chiều cao có thể thay đổi kích thước từ 110 dp đến 450 dp. Sau đó, bạn có thể đổi kích thước tiện ích từ 3x2 thành 5x2 ô, miễn là các điều kiện sau đây được đáp ứng:
- Thiết bị có lưới 5x4.
- Việc liên kết giữa số lượng ô và kích thước có sẵn trong dps tuân theo bảng cho thấy thông tin ước tính về kích thước tối thiểu trong trang này.
- Tiện ích này sẽ thích ứng với phạm vi kích thước đó.
Kotlin
val smallView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_small) val mediumView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_medium) val largeView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_large) val viewMapping: Map<SizeF, RemoteViews> = mapOf( SizeF(180f, 110f) to smallView, SizeF(270f, 110f) to mediumView, SizeF(270f, 280f) to largeView ) appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(viewMapping))
Java
RemoteViews smallView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_small); RemoteViews mediumView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_medium); RemoteViews largeView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_large); Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); viewMapping.put(new SizeF(180f, 110f), smallView); viewMapping.put(new SizeF(270f, 110f), mediumView); viewMapping.put(new SizeF(270f, 280f), largeView); RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews);
Giả sử tiện ích sử dụng bố cục thích ứng được xác định trong các đoạn mã trước đó. Điều này có nghĩa là bố cục được chỉ định là R.layout.widget_weather_forecast_small
được sử dụng từ 180 dp (minResizeWidth
) x 110 dp (minResizeHeight
) đến 269x279 dp (điểm cắt tiếp theo – 1). Tương tự, R.layout.widget_weather_forecast_medium
được dùng từ 270x110 dp đến 270x279 dp và R.layout.widget_weather_forecast_large
được dùng từ 270x280 dp đến 530 dp (maxResizeWidth
) x 450 dp (maxResizeHeight
).
Khi người dùng đổi kích thước tiện ích, giao diện của tiện ích cũng sẽ thay đổi để thích ứng với từng kích thước trong ô, như được minh hoạ trong các ví dụ sau.