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

ไฟล์ Manifest, ข้อมูลเมตา

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

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

หลังจากทำขั้นตอนการตั้งค่าเสร็จแล้ว ให้ประกาศ 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 แล้ว

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

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

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

ประกาศคลาสย่อย GlanceAppWidgetReceiver ของคุณเป็น Broadcast Receiver ในไฟล์ 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)

ใช้คลาส AppWidgetProvider

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

  • onUpdate(): Glance จะลบล้างโดยอัตโนมัติเพื่อดำเนินการอัปเดต องค์ประกอบ หากคุณลบล้าง onUpdate ด้วยตนเอง คุณต้องเรียกใช้ super.onUpdate เพื่อให้ Glance เปิดใช้การคอมโพส เธรดได้สำเร็จ
  • onAppWidgetOptionsChanged(): เรียกใช้เมื่อวางวิดเจ็ตเป็นครั้งแรกหรือ ปรับขนาด ตัวเลือกการอ่านแบบเหลือบจะจัดกลุ่มรายการไว้เบื้องหลังเพื่อให้เลย์เอาต์ ปรับเปลี่ยนได้อย่างราบรื่นตามขนาดรันไทม์
  • 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>