หน้านี้อธิบายการปรับแต่งขนาดวิดเจ็ตและความยืดหยุ่นที่มากขึ้นซึ่งเปิดตัวใน Android 12 (ระดับ API 31) รวมถึงรายละเอียดเกี่ยวกับวิธี ระบุขนาดของวิดเจ็ต
ใช้ API ที่ปรับปรุงแล้วสําหรับขนาดและเลย์เอาต์ของวิดเจ็ต
ตั้งแต่ Android 12 (ระดับ API 31) เป็นต้นไป คุณสามารถระบุแอตทริบิวต์ขนาดที่ละเอียดยิ่งขึ้นและเลย์เอาต์ที่ยืดหยุ่นได้มากขึ้นโดยทําตามขั้นตอนต่อไปนี้ตามที่อธิบายไว้ในส่วนต่างๆ ด้านล่าง
ใน Android เวอร์ชันก่อนหน้า คุณสามารถรับช่วงขนาดของวิดเจ็ตได้โดยใช้ส่วนเพิ่มเติม OPTION_APPWIDGET_MIN_WIDTH,OPTION_APPWIDGET_MIN_HEIGHT,OPTION_APPWIDGET_MAX_WIDTH,และ OPTION_APPWIDGET_MAX_HEIGHTแล้วประมาณขนาดของวิดเจ็ต แต่ตรรกะดังกล่าวใช้ไม่ได้ในทุกสถานการณ์ สําหรับวิดเจ็ตที่กําหนดเป้าหมายเป็น Android 12 ขึ้นไป เราขอแนะนําให้
ระบุ เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ หรือ เลย์เอาต์ที่แน่นอน
ระบุข้อจํากัดด้านขนาดของวิดเจ็ตเพิ่มเติม
Android 12 เพิ่ม API ที่ช่วยให้คุณมั่นใจได้ว่าวิดเจ็ตจะมีขนาดที่เชื่อถือได้มากขึ้นในอุปกรณ์ต่างๆ ที่มีขนาดหน้าจอแตกต่างกัน
นอกเหนือจากแอตทริบิวต์ minWidth,
minHeight,
minResizeWidth,
และ minResizeHeight
ที่มีอยู่แล้ว ให้ใช้แอตทริบิวต์ appwidget-provider ใหม่ต่อไปนี้
targetCellWidthและtargetCellHeight: กําหนดขนาดเป้าหมายของวิดเจ็ตในแง่ของเซลล์ตารางกริดของ Launcher หากมีการกําหนดแอตทริบิวต์เหล่านี้ ระบบจะใช้แอตทริบิวต์เหล่านี้แทนminWidthหรือminHeightmaxResizeWidthและmaxResizeHeight: กำหนดขนาดสูงสุดที่ Launcher อนุญาตให้ผู้ใช้ปรับขนาดวิดเจ็ต
XML ต่อไปนี้แสดงวิธีใช้แอตทริบิวต์การปรับขนาด
<appwidget-provider
...
android:targetCellWidth="3"
android:targetCellHeight="2"
android:maxResizeWidth="250dp"
android:maxResizeHeight="110dp">
</appwidget-provider>
ระบุเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์
หากเลย์เอาต์ต้องเปลี่ยนแปลงตามขนาดของวิดเจ็ต เราขอแนะนําให้สร้างเลย์เอาต์ชุดเล็กๆ ซึ่งแต่ละเลย์เอาต์ใช้ได้กับขนาดที่หลากหลาย หากทำไม่ได้ อีกทางเลือกหนึ่งคือการระบุเลย์เอาต์ตามขนาดที่แน่นอนของวิดเจ็ตในขณะรันไทม์ตามที่อธิบายไว้ในหน้านี้
ฟีเจอร์นี้ช่วยให้การปรับขนาดราบรื่นขึ้นและระบบโดยรวมมีประสิทธิภาพดีขึ้น เนื่องจากระบบไม่ต้องปลุกแอปทุกครั้งที่แสดงวิดเจ็ตในขนาดอื่น
ตัวอย่างโค้ดต่อไปนี้แสดงวิธีระบุรายการเลย์เอาต์
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); }
สมมติว่าวิดเจ็ตมีแอตทริบิวต์ต่อไปนี้
<appwidget-provider
android:minResizeWidth="160dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="250dp"
android:maxResizeHeight="200dp">
</appwidget-provider>
ข้อมูลโค้ดก่อนหน้านี้หมายความว่า
smallViewรองรับขนาดตั้งแต่ 160dp (minResizeWidth) × 110dp (minResizeHeight) ถึง 160dp × 199dp (จุดตัดถัดไป - 1dp)tallViewรองรับขนาดตั้งแต่ 160dp × 200dp ถึง 214dp (จุดตัดถัดไป - 1) × 200dpwideViewรองรับขนาดตั้งแต่ 215dp × 110dp (minResizeHeight) ถึง 250dp (maxResizeWidth) × 200dp (maxResizeHeight)
วิดเจ็ตต้องรองรับช่วงขนาดตั้งแต่ minResizeWidth × minResizeHeight ถึง maxResizeWidth × maxResizeHeight ภายในช่วงดังกล่าว คุณสามารถกำหนดจุดตัดเพื่อเปลี่ยนเลย์เอาต์ได้
ระบุเลย์เอาต์ที่แน่นอน
หากเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ชุดเล็กๆ ไม่สามารถใช้งานได้ คุณสามารถระบุเลย์เอาต์ต่างๆ ที่ปรับให้เหมาะกับขนาดที่แสดงวิดเจ็ตแทนได้ โดยปกติแล้วจะมี 2 ขนาดสําหรับโทรศัพท์ (โหมดแนวตั้งและโหมดแนวนอน) และ 4 ขนาดสําหรับอุปกรณ์พับได้
หากต้องการใช้โซลูชันนี้ แอปของคุณต้องทําตามขั้นตอนต่อไปนี้
โอเวอร์โหลด
AppWidgetProvider.onAppWidgetOptionsChanged(), ซึ่งจะเรียกใช้เมื่อชุดขนาดมีการเปลี่ยนแปลงเรียกใช้
AppWidgetManager.getAppWidgetOptions(), ซึ่งจะแสดงผลBundleที่มีขนาดเข้าถึงคีย์
AppWidgetManager.OPTION_APPWIDGET_SIZESจากBundle
ตัวอย่างโค้ดต่อไปนี้แสดงวิธีระบุเลย์เอาต์ที่แน่นอน
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) { }
ระบุขนาดของวิดเจ็ต
วิดเจ็ตแต่ละรายการต้องกําหนด targetCellWidth และ targetCellHeight สําหรับอุปกรณ์ที่ใช้ Android 12 ขึ้นไป หรือ minWidth และ minHeight สําหรับ Android ทุกเวอร์ชัน ซึ่งระบุพื้นที่ขั้นต่ำที่วิดเจ็ตใช้โดยค่าเริ่มต้น อย่างไรก็ตาม เมื่อผู้ใช้เพิ่มวิดเจ็ตลงในหน้าจอหลัก วิดเจ็ตมักจะใช้พื้นที่มากกว่าความกว้างและความสูงขั้นต่ำที่คุณระบุ
หน้าจอหลักของ Android มีตารางกริดของพื้นที่ว่างให้ผู้ใช้วางวิดเจ็ตและไอคอน ตารางกริดนี้อาจแตกต่างกันไปตามอุปกรณ์ เช่น โทรศัพท์มือถือหลายรุ่นมีตารางกริด 5x4 และแท็บเล็ตอาจมีตารางกริดขนาดใหญ่กว่า เมื่อเพิ่มวิดเจ็ต ระบบจะยืดวิดเจ็ตให้ใช้เซลล์จำนวนน้อยที่สุดในแนวนอนและแนวตั้งที่จําเป็นเพื่อให้เป็นไปตามข้อจํากัดสําหรับ targetCellWidth และ targetCellHeight ในอุปกรณ์ที่ใช้ Android 12 ขึ้นไป หรือข้อจํากัด minWidth และ minHeight ในอุปกรณ์ที่ใช้ Android 11 (ระดับ API 30) ลงไป
ทั้งความกว้างและความสูงของเซลล์ รวมถึงขนาดของระยะขอบอัตโนมัติที่ใช้กับวิดเจ็ตอาจแตกต่างกันไปในแต่ละอุปกรณ์ ใช้ตารางต่อไปนี้เพื่อประมาณขนาดขั้นต่ำของวิดเจ็ตในโทรศัพท์มือถือที่มีตารางกริด 5x4 ทั่วไป โดยพิจารณาจากจํานวนเซลล์ตารางกริดที่ต้องการ
| จํานวนเซลล์ (กว้าง x สูง) | ขนาดที่ใช้ได้ในโหมดแนวตั้ง (dp) | ขนาดที่ใช้ได้ในโหมดแนวนอน (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) |
ใช้ขนาดเซลล์ในโหมดแนวตั้งเพื่อกำหนดค่าที่คุณระบุสําหรับแอตทริบิวต์ minWidth, minResizeWidth และ maxResizeWidth ในทํานองเดียวกัน ให้ใช้ขนาดเซลล์ในโหมดแนวนอนเพื่อกำหนดค่าที่คุณระบุสําหรับแอตทริบิวต์ minHeight, minResizeHeight และ maxResizeHeight
เหตุผลก็คือโดยปกติแล้วความกว้างของเซลล์ในโหมดแนวตั้งจะเล็กกว่าในโหมดแนวนอน และในทํานองเดียวกัน ความสูงของเซลล์ในโหมดแนวนอนจะเล็กกว่าในโหมดแนวตั้ง
ตัวอย่างเช่น หากต้องการให้วิดเจ็ตมีความกว้างที่ปรับขนาดลงได้ถึง 1 เซลล์ใน Google Pixel 4 คุณต้องตั้งค่า minResizeWidth เป็น 56dp อย่างน้อยเพื่อให้แน่ใจว่าค่าสําหรับแอตทริบิวต์ minResizeWidth มีขนาดเล็กกว่า 57dp เนื่องจากเซลล์มีความกว้างอย่างน้อย 57dp ในโหมดแนวตั้ง
ในทํานองเดียวกัน หากต้องการให้วิดเจ็ตมีความสูงที่ปรับขนาดได้ใน 1 เซลล์ในอุปกรณ์เดียวกัน คุณต้องตั้งค่า minResizeHeight เป็น 50dp อย่างน้อยเพื่อให้แน่ใจว่าค่าสําหรับแอตทริบิวต์ minResizeHeight มีขนาดเล็กกว่า 51dp เนื่องจากเซลล์มีความสูงอย่างน้อย 51dp ในโหมดแนวนอน
วิดเจ็ตแต่ละรายการจะปรับขนาดได้ภายในช่วงขนาดระหว่างแอตทริบิวต์ minResizeWidth/minResizeHeight และ maxResizeWidth/maxResizeHeight ซึ่งหมายความว่าวิดเจ็ตต้องปรับให้เข้ากับช่วงขนาดใดก็ได้ระหว่างแอตทริบิวต์ดังกล่าว
ตัวอย่างเช่น หากต้องการตั้งค่าขนาดเริ่มต้นของวิดเจ็ตเมื่อวาง คุณสามารถตั้งค่าแอตทริบิวต์ต่อไปนี้
<appwidget-provider
android:targetCellWidth="3"
android:targetCellHeight="2"
android:minWidth="180dp"
android:minHeight="110dp">
</appwidget-provider>
ซึ่งหมายความว่าขนาดเริ่มต้นของวิดเจ็ตคือ 3x2 เซลล์ตามที่ระบุโดยแอตทริบิวต์ targetCellWidth และ targetCellHeight หรือ 180x110dp ตามที่ระบุโดย minWidth และ minHeight สําหรับอุปกรณ์ที่ใช้ Android 11 ลงไป ในกรณีหลัง ขนาดในเซลล์อาจแตกต่างกันไปตามอุปกรณ์
นอกจากนี้ หากต้องการตั้งค่าช่วงขนาดที่รองรับของวิดเจ็ต คุณสามารถตั้งค่าแอตทริบิวต์ต่อไปนี้
<appwidget-provider
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="530dp"
android:maxResizeHeight="450dp">
</appwidget-provider>
ตามที่ระบุโดยแอตทริบิวต์ก่อนหน้า ความกว้างของวิดเจ็ตจะปรับขนาดได้ตั้งแต่ 180dp ถึง 530dp และความสูงจะปรับขนาดได้ตั้งแต่ 110dp ถึง 450dp จากนั้นวิดเจ็ตจะปรับขนาดได้ตั้งแต่ 3x2 ถึง 5x2 เซลล์ ตราบใดที่เป็นไปตามเงื่อนไขต่อไปนี้
- อุปกรณ์มีตารางกริด 5x4
- การแมประหว่างจํานวนเซลล์กับขนาดที่ใช้ได้ใน dp เป็นไปตามตารางที่แสดงการประมาณขนาดขั้นต่ำ มิติในหน้านี้
- วิดเจ็ตปรับให้เข้ากับช่วงขนาดดังกล่าว
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);
สมมติว่าวิดเจ็ตใช้เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ซึ่งกําหนดไว้ในข้อมูลโค้ดก่อนหน้า ซึ่งหมายความว่าระบบจะใช้เลย์เอาต์ที่ระบุเป็น R.layout.widget_weather_forecast_small ตั้งแต่ 180dp (minResizeWidth) x 110dp (minResizeHeight) ถึง 269x279dp (จุดตัดถัดไป - 1) ในทํานองเดียวกัน ระบบจะใช้ R.layout.widget_weather_forecast_medium ตั้งแต่ 270x110dp ถึง 270x279dp และ R.layout.widget_weather_forecast_large ตั้งแต่ 270x280dp ถึง 530dp (maxResizeWidth) x 450dp (maxResizeHeight)
เมื่อผู้ใช้ปรับขนาดวิดเจ็ต ลักษณะที่ปรากฏของวิดเจ็ตจะเปลี่ยนไปเพื่อให้เหมาะกับขนาดแต่ละขนาดในเซลล์ ดังที่แสดงในตัวอย่างต่อไปนี้
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.