สร้างวิดเจ็ตแอปด้วย "ข้อมูลโดยย่อ"

ส่วนต่อไปนี้จะอธิบายวิธีสร้างวิดเจ็ตแอปพื้นฐานด้วย Glance

ประกาศ AppWidget ในไฟล์ Manifest

หลังจากทำตามขั้นตอนการตั้งค่าเสร็จแล้ว ให้ประกาศ AppWidget และข้อมูลเมตาของ AppWidget ในแอป

  1. ขยายตัวรับ AppWidget จาก GlanceAppWidgetReceiver โดยทำดังนี้

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
        override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget")
    }

  2. ลงทะเบียนผู้ให้บริการวิดเจ็ตแอปในไฟล์ AndroidManifest.xml และไฟล์ข้อมูลเมตาที่เกี่ยวข้อง

        <receiver android:name=".glance.MyReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/my_app_widget_info" />
    </receiver>
    

เพิ่มAppWidgetProviderInfoข้อมูลเมตา

จากนั้นทำตามคำแนะนำสร้างวิดเจ็ตเพื่อสร้างและกำหนดข้อมูลวิดเจ็ตแอปในไฟล์ @xml/my_app_widget_info

ความแตกต่างเพียงอย่างเดียวสำหรับ Glance คือไม่มี initialLayout XML แต่คุณต้องกำหนด คุณใช้เลย์เอาต์การโหลดที่กำหนดไว้ล่วงหน้าซึ่งมีอยู่ใน ไลบรารีได้

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>

ประกาศ XML ของ AppWidgetProviderInfo

ออบเจ็กต์ AppWidgetProviderInfo จะกำหนดคุณสมบัติที่สำคัญของวิดเจ็ต กำหนด AppWidgetProviderInfo ในไฟล์ทรัพยากรข้อมูลเมตา XML (res/xml/my_app_widget_info.xml) ภายในองค์ประกอบ <appwidget-provider> ดังนี้

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:targetCellWidth="1"
    android:targetCellHeight="1"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="120dp"
    android:updatePeriodMillis="86400000"
    android:description="@string/example_appwidget_description"
    android:previewLayout="@layout/example_appwidget_preview"
    android:initialLayout="@layout/glance_default_loading_layout"
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

แอตทริบิวต์การปรับขนาดวิดเจ็ต

หน้าจอหลักเริ่มต้นจะวางวิดเจ็ตในหน้าต่างตามตารางกริดของเซลล์ ที่มีความสูงและความกว้างที่กำหนดไว้ หน้าจอหลักส่วนใหญ่จะอนุญาตให้วิดเจ็ตมีขนาด เป็นจำนวนเต็มของเซลล์กริด เช่น 2 เซลล์ ในแนวนอนและ 3 เซลล์ในแนวตั้ง

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

ตารางต่อไปนี้จะอธิบายแอตทริบิวต์ <appwidget-provider> ที่เกี่ยวข้อง กับการปรับขนาดวิดเจ็ต

แอตทริบิวต์และคำอธิบาย
targetCellWidth และ targetCellHeight (Android 12) minWidth และ minHeight
  • ตั้งแต่ Android 12 เป็นต้นไป แอตทริบิวต์ targetCellWidth และ targetCellHeight จะระบุขนาดเริ่มต้นของวิดเจ็ตในแง่ของตารางกริด แอตทริบิวต์เหล่านี้จะไม่สนใจใน Android 11 และต่ำกว่า และอาจไม่สนใจหากหน้าจอหลักไม่ รองรับเลย์เอาต์แบบตารางกริด
  • แอตทริบิวต์ minWidth และ minHeight ระบุขนาดเริ่มต้นของวิดเจ็ต ในหน่วย dp หากค่าความกว้างหรือความสูงขั้นต่ำของวิดเจ็ตไม่ตรงกับ ขนาดของเซลล์ ระบบจะปัดเศษค่าขึ้นเป็น ขนาดเซลล์ที่ใกล้ที่สุด
เราขอแนะนำให้ระบุทั้ง 2 ชุดของ แอตทริบิวต์ ได้แก่ targetCellWidth และ targetCellHeight รวมถึง minWidth และ minHeight เพื่อให้แอปสามารถกลับไปใช้ minWidth และ minHeight ได้หากอุปกรณ์ของผู้ใช้ ไม่รองรับ targetCellWidth และ targetCellHeight หากรองรับ แอตทริบิวต์ targetCellWidth และ targetCellHeight จะมีความสำคัญเหนือกว่าแอตทริบิวต์ minWidth และ minHeight
minResizeWidth และ minResizeHeight ระบุขนาดขั้นต่ำสุดของวิดเจ็ต ค่าเหล่านี้จะระบุ ขนาดที่วิดเจ็ตอ่านไม่ออกหรือใช้ไม่ได้ การใช้แอตทริบิวต์เหล่านี้ช่วยให้ผู้ใช้ปรับขนาดวิดเจ็ตให้มีขนาดเล็กกว่า ขนาดเริ่มต้นของวิดเจ็ตได้ ระบบจะละเว้นแอตทริบิวต์ minResizeWidth หากมีค่ามากกว่า minWidth หรือหากไม่ได้เปิดใช้การปรับขนาดแนวนอน ดูresizeMode ในทำนองเดียวกัน ระบบจะละเว้นแอตทริบิวต์ minResizeHeight หากมีค่ามากกว่า minHeight หรือหากไม่ได้เปิดใช้การปรับขนาดแนวตั้ง
maxResizeWidth และ maxResizeHeight ระบุขนาดสูงสุดที่แนะนําของวิดเจ็ต หากค่าไม่ใช่ ผลคูณของขนาดเซลล์กริด ระบบจะปัดค่าขึ้นเป็นขนาดเซลล์ที่ใกล้เคียงที่สุด ระบบจะไม่สนใจแอตทริบิวต์ maxResizeWidth หากมีขนาดเล็กกว่า minWidth หรือหากไม่ได้เปิดใช้ การปรับขนาดแนวนอน ดู resizeMode ในทํานองเดียวกัน ระบบจะไม่สนใจแอตทริบิวต์ maxResizeHeight หากมีขนาดเล็กกว่า minHeight หรือหากไม่ได้เปิดใช้ การปรับขนาดแนวตั้ง เปิดตัวใน Android 12
resizeMode ระบุกฎเกณฑ์ที่ใช้ในการปรับขนาดวิดเจ็ต คุณสามารถใช้แอตทริบิวต์นี้เพื่อทำให้วิดเจ็ตหน้าจอหลักปรับขนาดได้ในแนวนอน แนวตั้ง หรือทั้ง 2 แกน ผู้ใช้แตะวิดเจ็ตค้างไว้เพื่อแสดงแฮนเดิลการปรับขนาด จากนั้นลากแฮนเดิลแนวนอนหรือแนวตั้งเพื่อเปลี่ยนขนาดในตารางกริดของเลย์เอาต์ ค่าสำหรับแอตทริบิวต์ resizeMode ได้แก่ horizontal, vertical และ none หากต้องการประกาศว่าวิดเจ็ตปรับขนาดได้ทั้งในแนวนอนและแนวตั้ง ให้ใช้ horizontal|vertical

ตัวอย่าง

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

  • เซลล์ตารางกริดมีความกว้าง 30 dp และสูง 50 dp
  • เราได้ระบุข้อกำหนดแอตทริบิวต์ต่อไปนี้
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="80dp"
    android:minHeight="80dp"
    android:targetCellWidth="2"
    android:targetCellHeight="2"
    android:minResizeWidth="40dp"
    android:minResizeHeight="40dp"
    android:maxResizeWidth="120dp"
    android:maxResizeHeight="120dp"
    android:resizeMode="horizontal|vertical" />

ตั้งแต่ Android 12 เป็นต้นไป

ใช้แอตทริบิวต์ targetCellWidth และ targetCellHeight เป็นขนาดเริ่มต้นของวิดเจ็ต

โดยค่าเริ่มต้น วิดเจ็ตจะมีขนาด 2x2 คุณสามารถปรับขนาดวิดเจ็ตให้เล็กลงเป็น 2x1 หรือใหญ่ขึ้นเป็น 4x3 ได้

Android 11 และต่ำกว่า

ใช้แอตทริบิวต์ minWidth และ minHeight เพื่อคำนวณขนาดเริ่มต้นของ วิดเจ็ต

ความกว้างเริ่มต้น = Math.ceil(80 / 30) = 3

ความสูงเริ่มต้น = Math.ceil(80 / 50) = 2

โดยค่าเริ่มต้นวิดเจ็ตจะมีขนาด 3x2 คุณปรับขนาดวิดเจ็ตให้เล็กลงได้ถึง 2x1 หรือขยายให้เต็มหน้าจอ

แอตทริบิวต์วิดเจ็ตเพิ่มเติม

ตารางต่อไปนี้อธิบายแอตทริบิวต์ <appwidget-provider> ที่เกี่ยวข้อง กับคุณภาพอื่นๆ นอกเหนือจากการปรับขนาดวิดเจ็ต

แอตทริบิวต์และคำอธิบาย
updatePeriodMillis กำหนดความถี่ที่เฟรมเวิร์กวิดเจ็ตจะขออัปเดตจาก GlanceAppWidgetReceiver โดยการเรียกใช้เมธอด Callback onUpdate() เราขอแนะนำให้อัปเดตให้น้อยที่สุดเท่าที่จะเป็นไปได้ ซึ่งไม่เกิน 1 ครั้งต่อชั่วโมง เพื่อประหยัดแบตเตอรี่ ดูรายละเอียดได้ที่ส่วนเวลาที่ควรอัปเดตวิดเจ็ตในการจัดการสถานะ Glance
initialLayout ชี้ไปยังทรัพยากรเลย์เอาต์ที่กำหนดเลย์เอาต์การโหลดของวิดเจ็ตก่อนที่องค์ประกอบ Glance UI จะแสดงผล คุณสามารถใช้เลย์เอาต์การโหลดที่กำหนดไว้ล่วงหน้าซึ่งมีอยู่ในไลบรารี @layout/glance_default_loading_layout
configure กำหนดกิจกรรมการกำหนดค่าที่จะเปิดขึ้นเมื่อผู้ใช้เพิ่มวิดเจ็ต ดูส่วนใช้กิจกรรมการกำหนดค่าวิดเจ็ตในหน้านี้
description ระบุคำอธิบายสำหรับเครื่องมือเลือกวิดเจ็ตเพื่อแสดงสำหรับวิดเจ็ตของคุณ เปิดตัวใน Android 12
previewLayout (Android 12) และ previewImage (Android 11 และต่ำกว่า)
  • ตั้งแต่ Android 12 เป็นต้นไป แอตทริบิวต์ previewLayout จะระบุตัวอย่างที่ปรับขนาดได้ ซึ่ง คุณระบุเป็นเลย์เอาต์ XML ที่ตั้งค่าเป็นขนาดเริ่มต้นของวิดเจ็ต ในอุดมคติ สิ่งนี้จะชี้ไปยังการแมป XML แบบคงที่ที่ตรงกับเลย์เอาต์การออกแบบของคุณ
  • ใน Android 11 หรือต่ำกว่า แอตทริบิวต์ previewImage จะระบุภาพหน้าจอแบบคงที่ที่วาดได้ของลักษณะวิดเจ็ต ซึ่งจะปรากฏในเครื่องมือเลือกวิดเจ็ต
เราขอแนะนำให้ระบุทั้ง 2 อย่างเพื่อให้แอปของคุณกลับไปใช้แพลตฟอร์มรุ่นเก่าได้อย่างราบรื่น สำหรับแพลตฟอร์มใหม่กว่า (Android 15 ขึ้นไป) คุณสามารถกำหนดตัวอย่างที่สร้างขึ้นแบบเรียลไทม์ใน Kotlin ได้โดยใช้ `GlanceAppWidget.providePreview` ดูคู่มือตัวอย่างที่สร้างขึ้น
autoAdvanceViewId ระบุรหัสมุมมองของมุมมองย่อยของวิดเจ็ตที่โฮสต์ของวิดเจ็ตเปลี่ยนหน้าโดยอัตโนมัติ
widgetCategory ประกาศว่าวิดเจ็ตแสดงในหน้าจอหลัก (home_screen), หน้าจอล็อก (keyguard) หรือทั้ง 2 หน้าจอได้หรือไม่ สำหรับ Android 5.0 ขึ้นไป จะใช้ได้เฉพาะ home_screen
widgetFeatures ประกาศฟีเจอร์ที่วิดเจ็ตรองรับ เช่น หากการกำหนดค่าวิดเจ็ตเป็นแบบไม่บังคับ ให้ระบุทั้ง configuration_optional และ reconfigurable

กำหนด GlanceAppWidget

  1. สร้างคลาสใหม่ที่ขยายจาก GlanceAppWidget และลบล้าง เมธอด provideGlance นี่คือวิธีที่คุณสามารถโหลดข้อมูลที่จำเป็นต่อการแสดงผลวิดเจ็ต

    class MyAppWidget : GlanceAppWidget() {
    
        override suspend fun provideGlance(context: Context, id: GlanceId) {
    
            // In this method, load data needed to render the AppWidget.
            // Use `withContext` to switch to another thread for long running
            // operations.
    
            provideContent {
                // create your AppWidget here
                Text("Hello World")
            }
        }
    }

  2. สร้างอินสแตนซ์ใน glanceAppWidget บน GlanceAppWidgetReceiver ของคุณ

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
    
        // Let MyAppWidgetReceiver know which GlanceAppWidget to use
        override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
    }

ตอนนี้คุณได้กำหนดค่า AppWidget โดยใช้ Glance แล้ว

ใช้คลาส GlanceAppWidgetReceiver เพื่อจัดการการออกอากาศวิดเจ็ต

วิดเจ็ตพิกัด GlanceAppWidgetReceiver จะออกอากาศและอัปเดตสถานะแพลตฟอร์ม โดยการขยาย AppWidgetProvider พื้นฐาน วิดเจ็ตจะรับ เหตุการณ์ของแพลตฟอร์มเมื่อมีการอัปเดต ลบ เปิดใช้ หรือปิดใช้ วิดเจ็ต แล้วแปลเป็นคำขอวงจร Compose

ประกาศวิดเจ็ตในไฟล์ Manifest

ประกาศคลาสย่อย GlanceAppWidgetReceiver ของคุณเป็นเครื่องรับการออกอากาศในไฟล์ AndroidManifest.xml ดังนี้

<receiver android:name="ExampleAppWidgetReceiver"
          android:exported="false">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/my_app_widget_info" />
</receiver>

องค์ประกอบ <receiver> ต้องมีแอตทริบิวต์ android:name ซึ่งระบุคลาสตัวรับ ผู้รับต้องยอมรับACTION_APPWIDGET_UPDATE การดำเนินการออกอากาศภายใน <intent-filter>

องค์ประกอบ <meta-data> ต้องระบุชื่อเป็น android.appwidget.provider และแอตทริบิวต์ android:resource ต้องชี้ไปยัง แหล่งข้อมูลเมตา XML ของ AppWidgetProviderInfo (@xml/my_app_widget_info)

ใช้คลาส GlanceAppWidgetReceiver

ใน Glance คุณจะขยาย GlanceAppWidgetReceiver แทน AppWidgetProvider โดยตรงได้โดยลิงก์ตัวรับสัญญาณกับอินสแตนซ์ GlanceAppWidget GlanceAppWidgetReceiver ของคุณ การเรียกกลับหลักที่ใช้ได้ใน GlanceAppWidgetReceiver จะทำงานดังนี้

  • onUpdate(): Glance จะลบล้างโดยอัตโนมัติเพื่อดำเนินการอัปเดตการคอมโพส หากคุณลบล้าง onUpdate ด้วยตนเอง คุณต้องเรียกใช้ super.onUpdate เพื่อให้ Glance เปิดใช้เธรดการคอมโพส ได้สำเร็จ
  • onAppWidgetOptionsChanged(): เรียกใช้เมื่อวางหรือปรับขนาดวิดเจ็ตเป็นครั้งแรก Glance จะอ่านรายการในชุดตัวเลือกเบื้องหลังเพื่อให้เลย์เอาต์ปรับตามขนาดรันไทม์ได้อย่างราบรื่น
  • onDeleted(Context, IntArray): เรียกใช้ทุกครั้งที่ผู้ใช้ลบวิดเจ็ต อินสแตนซ์ที่เฉพาะเจาะจง
  • onEnabled(Context): ทริกเกอร์เมื่อสร้างอินสแตนซ์แรกของวิดเจ็ตสำเร็จ เหมาะอย่างยิ่งสำหรับการย้ายข้อมูลทั่วโลก
  • onDisabled(Context): เรียกใช้เมื่อนำอินสแตนซ์สุดท้ายที่ใช้งานอยู่ของ ผู้ให้บริการออก
  • onReceive(Context, Intent): สกัดกั้นการออกอากาศของทุกแพลตฟอร์มก่อน เมธอดการเรียกกลับที่เฉพาะเจาะจง คุณต้องตรวจสอบว่าตรรกะตัวรับสัญญาณที่กำหนดเอง ที่คุณเขียนเรียกใช้ super.onReceive(context, intent) และห้ามเรียกใช้ goAsync ด้วยตนเอง เนื่องจาก Glance จะกำหนดเส้นทางการทำงานโดยอัตโนมัติ แบบไม่พร้อมกัน

รับ Intent การออกอากาศของวิดเจ็ต

GlanceAppWidgetReceiverจะกรองและจัดการเจตนาการออกอากาศวิดเจ็ตแพลตฟอร์มพื้นฐานต่อไปนี้

สร้าง UI

ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้าง UI

/* Import Glance Composables
 In the event there is a name clash with the Compose classes of the same name,
 you may rename the imports per https://kotlinlang.org/docs/packages.html#imports
 using the `as` keyword.

import androidx.glance.Button
import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.text.Text
*/
class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // Load data needed to render the AppWidget.
        // Use `withContext` to switch to another thread for long running
        // operations.

        provideContent {
            // create your AppWidget here
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        Column(
            modifier = GlanceModifier.fillMaxSize(),
            verticalAlignment = Alignment.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button(
                    text = "Home",
                    onClick = actionStartActivity<MyActivity>()
                )
                Button(
                    text = "Work",
                    onClick = actionStartActivity<MyActivity>()
                )
            }
        }
    }
}

ตัวอย่างโค้ดก่อนหน้าจะทำสิ่งต่อไปนี้

  • ในระดับบนสุด Column ระบบจะวางรายการในแนวตั้งต่อกัน
  • Column จะขยายขนาดให้พอดีกับพื้นที่ว่าง (ผ่าน GlanceModifier) และจัดเนื้อหาให้อยู่ด้านบน (verticalAlignment) และจัดกึ่งกลางในแนวนอน (horizontalAlignment)
  • เนื้อหาของ Column จะกำหนดโดยใช้ Lambda ลำดับมีความสำคัญ
    • รายการแรกใน Column คือคอมโพเนนต์ Text ที่มีระยะขอบ 12.dp
    • รายการที่ 2 คือ Row ซึ่งวางรายการในแนวนอนต่อกัน โดยมี Buttons 2 รายการวางกึ่งกลางในแนวนอน (horizontalAlignment) การแสดงผลสุดท้ายขึ้นอยู่กับพื้นที่ว่างที่มี รูปภาพต่อไปนี้เป็นตัวอย่างลักษณะที่อาจปรากฏ
วิดเจ็ตปลายทาง
รูปที่ 1 ตัวอย่าง UI

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

ใช้มุมโค้งมน

Android 12 เปิดตัวพารามิเตอร์ของระบบเพื่อปรับแต่งรัศมีมุมของวิดเจ็ตแอปแบบไดนามิก ดังนี้

  • system_app_widget_background_radius: ระบุรัศมีมุมของคอนเทนเนอร์พื้นหลังของวิดเจ็ต (ไม่เกิน 28 dp)
  • รัศมีด้านใน: เพื่อป้องกันไม่ให้เนื้อหาถูกตัด ให้คำนวณรัศมีที่ได้สัดส่วน สำหรับเนื้อหาด้านในตามโครงร่างพื้นหลังของระบบ systemRadiusValue - widgetPadding

ใน Glance คุณสามารถใช้พร็อพเพอร์ตี้การกำหนดขนาดรัศมีมุมแบบไดนามิกใน องค์ประกอบโดยใช้ GlanceModifier.cornerRadius(android.R.dimen.system_app_widget_background_radius)

หากต้องการความเข้ากันได้แบบย้อนหลังในอุปกรณ์ที่ใช้ Android 11 (ระดับ API 30) หรือต่ำกว่า ให้ใช้แอตทริบิวต์ที่กำหนดเองและธีมสำรองที่กำหนดเอง

  • /values/attrs.xml

    <resources>
    <attr name="backgroundRadius" format="dimension" />
    </resources>
    
  • /values/styles.xml

    <resources>
    <style name="MyWidgetTheme">
      <item name="backgroundRadius">@dimen/my_background_radius_dimen</item>
    </style>
    </resources>
    
  • /values-31/styles.xml

    <resources>
    <style name="MyWidgetTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
      <item name="backgroundRadius">@android:dimen/system_app_widget_background_radius</item>
    </style>
    </resources>
    
  • /drawable/my_widget_background.xml

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="?attr/backgroundRadius" />
    </shape>