Trang này mô tả các điểm tinh chỉnh về kích thước tiện ích và tính linh hoạt cao hơn được giới thiệu trong Android 12 (cấp độ API 31). Trang 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.
Sử dụng API cải tiến cho kích thước và bố cục tiện ích
Kể từ Android 12 (cấp độ API 31), bạn có thể cung cấp các thuộc tính kích thước tinh chỉnh hơn và bố cục linh hoạt bằng cách thực hiện những việc sau, như mô tả trong các phần tiếp theo:
Chỉ định các quy tắc ràng buộc bổ sung về kích thước tiện ích.
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, bạn có thể lấy phạm vi kích thước của một
tiện ích bằng cách sử dụng các
OPTION_APPWIDGET_MIN_WIDTH,
OPTION_APPWIDGET_MIN_HEIGHT,
OPTION_APPWIDGET_MAX_WIDTH,
và OPTION_APPWIDGET_MAX_HEIGHT
phần bổ sung, sau đó ước tính kích thước của tiện ích, nhưng logic đó không hoạt động trong mọi
trường hợp. Đối với các tiện ích nhắm đến Android 12 trở lên, bạn nên cung cấp bố cục thích ứng hoặc bố cục chính xác.
Chỉ định các quy tắc ràng buộc bổ sung về kích thước tiện ích
Android 12 bổ sung các API cho phép bạn đảm bảo tiện ích của mình được định kích thước đá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 đây:
targetCellWidthvàtargetCellHeight: xác định kích thước mục tiêu của tiện ích theo ô 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 chominWidthhoặcminHeight.maxResizeWidthvà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 nhóm nhỏ các bố cục, mỗi bố cục hợp lệ cho một phạm vi kích thước. Nếu không thể thực hiện việc này, bạn có thể cung cấp bố cục dựa trên kích thước chính xác của tiện ích trong thời gian chạy, như mô tả trong trang này.
Tính năng này cho phép điều chỉnh tỷ lệ mượt mà hơn và cải thiện tình trạng chung của hệ thống, vì hệ thống không phải đánh thức ứng dụng mỗi khi hiển thị tiện ích ở một kích thước khác.
Ví dụ về mã sau đây cho biết 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:
smallViewhỗ trợ từ 160 dp (minResizeWidth) × 110 dp (minResizeHeight) đến 160 dp × 199 dp (điểm ngắt tiếp theo – 1 dp).tallViewhỗ trợ từ 160 dp × 200 dp đến 214 dp (điểm ngắt tiếp theo – 1) × 200 dp.wideViewhỗ trợ từ 215 dp × 110 dp (minResizeHeight) đến 250 dp (maxResizeWidth) × 200 dp (maxResizeHeight).
Tiện ích của bạn phải hỗ trợ phạm vi kích thước 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 các bố cục khác nhau phù hợp với kích thước mà tiện ích được hiển thị. Thông thường, có 2 kích thước cho điện thoại (chế độ dọc và chế độ 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:
Nạp chồng
AppWidgetProvider.onAppWidgetOptionsChanged(), được gọi khi tập hợp kích thước thay đổi.Gọi
AppWidgetManager.getAppWidgetOptions(), trả về mộtBundlechứa các kích thước.Truy cập vào khoá
AppWidgetManager.OPTION_APPWIDGET_SIZEStừBundle.
Ví dụ về mã sau đây cho biết 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 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ả các phiên bản Android – cho biết lượng không gian tối thiểu mà tiện ích tiêu thụ theo mặc định. Tuy nhiên, khi người dùng thêm tiện ích vào màn hình chính, tiện ích đó 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 thiết bị cầm tay 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 vào, tiện ích của bạn sẽ được kéo giãn để chiếm số ô 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 (cấp độ API 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 các lề tự động được áp dụng cho tiện ích có thể khác nhau trên các thiết bị. Hãy sử dụng bảng sau đây để ước tính sơ bộ kích thước tối thiểu của tiện ích trong một thiết bị cầm tay có lưới 5x4 thông thường, dựa trên số ô lưới đã chiếm 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 | 57x102dp | 127x51dp |
| 2x1 | 130x102dp | 269x51dp |
| 3x1 | 203x102dp | 412x51dp |
| 4x1 | 276x102dp | 554x51dp |
| 5x1 | 349x102dp | 697x51dp |
| 5x2 | 349x220dp | 697x117dp |
| 5x3 | 349x337dp | 697x184dp |
| 5x4 | 349x455dp | 697x250dp |
| ... | ... | ... |
| n x m | (73n – 16) x (118m – 16) | (142n – 15) x (66m – 15) |
Sử dụng kích thước ô ở chế độ dọc để cung cấp các giá trị cho thuộc tính minWidth, minResizeWidth và maxResizeWidth. Tương tự, hãy sử dụng kích thước ô ở chế độ ngang để cung cấp các giá trị cho thuộc tính minHeight, minResizeHeight và maxResizeHeight.
Lý do là vì chiều rộng ô thường nhỏ hơn ở chế độ dọc so với chế độ ngang – và tương tự, chiều cao ô 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 xuống còn 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ị cho thuộc tính minResizeWidth nhỏ hơn 57 dp – vì một ô có chiều rộng ít nhất là 57 dp ở chế độ dọc.
Tương tự, nếu bạn muốn chiều cao 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 thành tối đa 50 dp để đảm bảo giá trị cho thuộc tính minResizeHeight nhỏ hơn 51 dp – vì một ô có chiều cao ít nhất là 51 dp ở chế độ ngang.
Mỗi tiện ích có thể đổi kích thước trong phạm vi kích thước giữa các thuộc tính minResizeWidth/minResizeHeight và maxResizeWidth/maxResizeHeight, nghĩa 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 khi đặt, bạn có thể đặt 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, như được chỉ định bởi minWidth và minHeight cho các thiết bị chạy Android 11 trở xuống. Trong trường hợp sau, kích thước theo ô 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ư được chỉ định bởi các thuộc tính trước đó, chiều rộng của tiện ích có thể đổi kích thước từ 180 dp thành 530 dp và chiều cao của tiện ích có thể đổi kích thước từ 110 dp thành 450 dp. Sau đó, tiện ích có thể đổi kích thước từ 3x2 ô thành 5x2 ô, miễn là có các điều kiện sau:
- Thiết bị có lưới 5x4.
- Việc ánh xạ giữa số ô và kích thước có sẵn theo dp tuân theo bảng cho thấy ước tính về kích thước tối thiểu chiều trong trang này.
- Tiện ích 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 các 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 ngắt tiếp theo – 1). Tương tự, R.layout.widget_weather_forecast_medium được sử dụng từ 270x110 dp đến 270x279 dp và R.layout.widget_weather_forecast_large được sử 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 sẽ thay đổi để thích ứng với từng kích thước theo ô, như trong các ví dụ sau.
R.layout.widget_weather_forecast_small.
R.layout.widget_weather_forecast_medium.
R.layout.widget_weather_forecast_medium.
R.layout.widget_weather_forecast_large.
R.layout.widget_weather_forecast_large.