มีเลย์เอาต์วิดเจ็ตที่ยืดหยุ่น

หน้านี้อธิบายการปรับแต่งเพื่อปรับขนาดวิดเจ็ตและความยืดหยุ่นที่มากขึ้น เปิดตัวใน Android 12 (API ระดับ 31) และยังบอกรายละเอียดวิธีการ ระบุขนาดของวิดเจ็ต

ใช้ API ที่ปรับปรุงแล้วสำหรับขนาดและเลย์เอาต์วิดเจ็ต

ตั้งแต่ Android 12 (API ระดับ 31) เป็นต้นไป คุณจะระบุขนาดที่ละเอียดยิ่งขึ้นได้ และเลย์เอาต์ที่ยืดหยุ่นได้โดยทำดังนี้ ดังที่อธิบายไว้ใน ส่วนต่างๆ ที่ตามมา:

  1. ระบุข้อจำกัดเกี่ยวกับขนาดวิดเจ็ตเพิ่มเติม

  2. การมีเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์หรือเลย์เอาต์ที่ตรงกันทุกประการ

ใน 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 หรือ minHeight

  • maxResizeWidth และ 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 รองรับตั้งแต่ 160 dp (minResizeWidth) × 110 dp (minResizeHeight) ถึง 160dp × 199dp (จุดตัดถัดไปคือ 1dp)
  • tallView รองรับขนาดตั้งแต่ 160dp × 200dp ถึง 214dp (จุดตัดถัดไป - 1) × 200dp
  • wideView รองรับตั้งแต่ 215dp × 110dp (minResizeHeight) ถึง 250dp (maxResizeWidth) × 200dp (maxResizeHeight)

วิดเจ็ตต้องรองรับขนาดตั้งแต่ minResizeWidth × minResizeHeight ถึง maxResizeWidth × maxResizeHeight ภายในช่วงดังกล่าว คุณสามารถเลือกจุดตัดเพื่อเปลี่ยนเลย์เอาต์ได้

ตัวอย่างเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์
รูปที่ 1 ตัวอย่างเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์

แสดงเลย์เอาต์ที่แน่นอน

หากไม่สามารถใช้เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ชุดเล็กๆ ให้คุณระบุ รูปแบบต่างๆ ที่ปรับแต่งให้เหมาะกับขนาดที่วิดเจ็ตแสดง ซึ่งโดยทั่วไปแล้วจะมี 2 ขนาดสําหรับโทรศัพท์ (โหมดแนวตั้งและแนวนอน) และ 4 ขนาดสําหรับโทรศัพท์แบบพับได้

ในการใช้โซลูชันนี้ แอปของคุณต้องทำตามขั้นตอนต่อไปนี้

  1. โอเวอร์โหลด AppWidgetProvider.onAppWidgetOptionsChanged() ซึ่งจะถูกเรียกเมื่อชุดของขนาดมีการเปลี่ยนแปลง

  2. เรียก AppWidgetManager.getAppWidgetOptions() ซึ่งจะแสดงผล Bundle ที่มีขนาด

  3. เข้าถึงคีย์ 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
... ... ...
กว้าง x ม. (73n - 16) x (118m - 16) (142n - 15) x (66m - 15)

ใช้ขนาดเซลล์ในโหมดแนวตั้งเพื่อแจ้งค่าที่คุณระบุสำหรับ แอตทริบิวต์ minWidth, minResizeWidth และ maxResizeWidth ในทำนองเดียวกัน ให้ใช้ขนาดเซลล์ในโหมดแนวนอนเพื่อระบุค่าที่คุณระบุสำหรับแอตทริบิวต์ minHeight, minResizeHeight และ maxResizeHeight

เนื่องจากโดยทั่วไปแล้วความกว้างของเซลล์จะน้อยกว่าในโหมดแนวตั้ง เมื่อเทียบกับโหมดแนวนอน และในทำนองเดียวกัน ความสูงของเซลล์มักจะ ในโหมดแนวนอนจะมีขนาดเล็กกว่าในโหมดแนวตั้ง

ตัวอย่างเช่น หากคุณต้องการปรับขนาดความกว้างของวิดเจ็ตให้เล็กลงเหลือเพียงเซลล์เดียว Google Pixel 4 คุณต้องตั้งค่าminResizeWidthไม่เกิน 56dp เพื่อตรวจสอบว่าค่าสำหรับแอตทริบิวต์ minResizeWidth เล็กลง 57dp เนื่องจากเซลล์กว้างอย่างน้อย 57dp ในแนวตั้ง ในทำนองเดียวกัน หากคุณต้องการปรับขนาดความสูงของวิดเจ็ตได้ในเซลล์เดียว อุปกรณ์เดียวกัน คุณต้องตั้งค่า 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 หรือ 180×110dp ตามขนาด ระบุโดย 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 เซลล์ตราบเท่าที่เป็นไปตามเงื่อนไขต่อไปนี้ ที่มีอยู่:

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)

เมื่อผู้ใช้ปรับขนาดวิดเจ็ต ลักษณะที่ปรากฏของวิดเจ็ตจะเปลี่ยนไปเพื่อปรับให้เข้ากับขนาดแต่ละขนาดในเซลล์ ดังที่แสดงในตัวอย่างต่อไปนี้

ตัวอย่างวิดเจ็ตสภาพอากาศในขนาดตารางกริด 3x2 ที่เล็กที่สุด UI แสดง
            ชื่อสถานที่ (โตเกียว) อุณหภูมิ (14°) และสัญลักษณ์ที่ระบุ
            สภาพอากาศมีเมฆบางส่วน
รูปที่ 2 3x2 R.layout.widget_weather_forecast_small

ตัวอย่างวิดเจ็ตสภาพอากาศขนาด 4x2 &quot;กลาง&quot; การปรับขนาดวิดเจ็ต
            ด้วยวิธีนี้ วิดเจ็ตจะสร้างขึ้นบน UI ทั้งหมดจากขนาดวิดเจ็ตก่อนหน้า
            และเพิ่มป้ายกำกับ &quot;มีเมฆเป็นส่วนใหญ่&quot; และการคาดการณ์อุณหภูมิตั้งแต่
            16:00 น. - 19:00 น.
รูปที่ 3 4x2 R.layout.widget_weather_forecast_medium

ตัวอย่างวิดเจ็ตสภาพอากาศขนาด &quot;กลาง&quot; 5x2 การปรับขนาดวิดเจ็ต
            วิธีนี้จะทำให้ดู UI เหมือนกับขนาดก่อนหน้านี้ ยกเว้นว่า
            ยืดออกหนึ่งเซลล์เพื่อกินพื้นที่ในแนวนอนมากขึ้น
รูปที่ 4 5x2 R.layout.widget_weather_forecast_medium

ตัวอย่างวิดเจ็ตสภาพอากาศขนาด &quot;ใหญ่&quot; 5x3 การปรับขนาดวิดเจ็ต
            ด้วยวิธีนี้ จะต่อยอดไปบน UI ทั้งหมดจากขนาดวิดเจ็ตก่อนหน้านี้
            และเพิ่มมุมมองภายในวิดเจ็ตที่มีพยากรณ์อากาศ
            ในวันอังคารและวันพุธ สัญลักษณ์แสดงสภาพอากาศที่มีแดดจัดหรือฝนตก
            และอุณหภูมิสูงสุดและต่ำสุดของแต่ละวัน
รูปที่ 5 5x3 R.layout.widget_weather_forecast_large

ตัวอย่างวิดเจ็ตสภาพอากาศขนาด &quot;ใหญ่&quot; 5x4 การปรับขนาดวิดเจ็ตด้วยวิธีนี้จะอิงตาม UI ทั้งหมดจากขนาดวิดเจ็ตก่อนหน้า และเพิ่มวันพฤหัสบดีและวันศุกร์ (และสัญลักษณ์ที่เกี่ยวข้องซึ่งระบุประเภทของสภาพอากาศ รวมถึงอุณหภูมิสูงสุดและต่ำของแต่ละวัน)
รูปที่ 6 5x4 R.layout.widget_weather_forecast_large