יצירת ווידג'ט פשוט

ווידג'טים של אפליקציות הם תצוגות מוקטנות של אפליקציות שאפשר להטמיע באפליקציות אחרות – כמו מסך הבית – ולקבל עדכונים תקופתיים. התצוגות האלה נקראות ווידג'טים בממשק המשתמש, ואפשר לפרסם אחת מהן באמצעות ספק ווידג'טים של אפליקציה (או ספק ווידג'טים). רכיב אפליקציה שמכיל ווידג'טים אחרים נקרא מארח ווידג'טים של אפליקציה (או מארח ווידג'טים). באיור 1 מוצג ווידג'ט מוזיקה לדוגמה:

דוגמה לווידג'ט מוזיקה
איור 1. דוגמה לווידג'ט מוזיקה.

במסמך הזה מוסבר איך לפרסם ווידג'ט באמצעות ספק ווידג'טים. לפרטים נוספים על יצירת AppWidgetHost משלכם לאירוח ווידג'טים של אפליקציות, ראו איך יוצרים מארח ווידג'טים.

בסקירה הכללית על ווידג'טים של אפליקציות מוסבר איך מעצבים ווידג'טים.

רכיבי ווידג'טים

כדי ליצור ווידג'ט, צריך את הרכיבים הבסיסיים הבאים:

אובייקט AppWidgetProviderInfo
תיאור המטא-נתונים של ווידג'ט, כמו הפריסה של הווידג'ט, תדירות העדכון והקלאס AppWidgetProvider. AppWidgetProviderInfo מוגדר ב-XML, כפי שמתואר במסמך הזה.
הכיתה AppWidgetProvider
מגדיר את השיטות הבסיסיות שמאפשרות ליצור ממשק עם הווידג'ט באופן פרוגרמטי. דרך האירוע הזה תקבלו עדכונים כשהווידג'ט מתעדכן, מופעל, מושבת או נמחק. מגדירים את AppWidgetProvider במניפסט ואז מטמיעים אותו, כפי שמתואר במסמך הזה.
הצגת הפריסה
מגדירה את הפריסה הראשונית של הווידג'ט. הפריסה מוגדרת ב-XML, כפי שמתואר במסמך הזה.

איור 2 מראה איך הרכיבים האלה משתלבים בתהליך העיבוד הכולל של הווידג'ט של האפליקציה.

תהליך העיבוד של ווידג'טים של אפליקציות
איור 2. תהליך העיבוד של ווידג'ט של אפליקציה.

אם לווידג'ט יש צורך בהגדרות המשתמש, צריך להטמיע את פעילות ההגדרה של הווידג'ט של האפליקציה. הפעילות הזו מאפשרת למשתמשים לשנות את הגדרות הווידג'ט, לדוגמה, אזור הזמן לווידג'ט של שעון.

אנחנו ממליצים גם על השיפורים הבאים: פריסות גמישות של ווידג'טים, שיפורים שונים, ווידג'טים מתקדמים, ווידג'טים של אוספים ובניית מארח של ווידג'טים.

הצהרה על קובץ ה-XML של AppWidgetProviderInfo

האובייקט AppWidgetProviderInfo מגדיר את התכונות החיוניות של ווידג'ט. מגדירים את האובייקט AppWidgetProviderInfo בקובץ משאב XML באמצעות רכיב <appwidget-provider> יחיד ושומרים אותו בתיקייה res/xml/ של הפרויקט.

אפשר לראות זאת בדוגמה הבאה:

<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/example_loading_appwidget"
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

מאפייני התאמת הגודל של ווידג'טים

ברירת המחדל של מסך הבית ממקמת ווידג'טים בחלון על סמך רשת של תאים עם גובה ורוחב מוגדרים. ברוב מסכי הבית, הווידג'טים יכולים להיות רק בגדלים שהם מכפילים שלמים של תאי הרשת – לדוגמה, שני תאים אופקיים על שלושה תאים אנכיים.

מאפייני הגודל של הווידג'ט מאפשרים לכם לציין גודל ברירת מחדל לווידג'ט ולספק גבולות עליון ותחתון לגודל הווידג'ט. בהקשר הזה, גודל ברירת המחדל של הווידג'ט הוא הגודל שהוא מקבל כשמוסיפים אותו בפעם הראשונה למסך הבית.

בטבלה הבאה מתוארים המאפיינים של <appwidget-provider> שקשורים לגודל הווידג'ט:

מאפיינים ותיאור
targetCellWidth ו-targetCellHeight (Android 12),‏ minWidth ו-minHeight
  • החל מגרסה Android 12, המאפיינים targetCellWidth ו-targetCellHeight מציינים את גודל ברירת המחדל של הווידג'ט במונחים של תאי רשת. ב-Android 11 ומטה אפשר להתעלם מהמאפיינים האלה, ואפשר להתעלם מהם אם מסך הבית לא תומך בפריסה שמבוססת על רשת.
  • המאפיינים minWidth ו-minHeight מציינים את גודל ברירת המחדל של הווידג'ט ב-dp. אם ערכי הרוחב או הגובה המינימלי של הווידג'ט לא תואמים למידות של התאים, הערכים יעוגלו כלפי מעלה בהתאם לגודל התא הקרוב ביותר.
מומלץ לציין את שתי קבוצות המאפיינים – 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 קובע את הכללים שבאמצעותם אפשר לשנות את גודל הווידג'ט. אפשר להשתמש במאפיין הזה כדי לשנות את הגודל של ווידג'טים במסך הבית אופקית, אנכית או בשני הצירים. המשתמשים לוחצים לחיצה ארוכה על ווידג'ט כדי להציג את נקודות האחיזה לשינוי הגודל, ואז גוררים את נקודות האחיזה האופקיות או האנכיות כדי לשנות את הגודל שלו בתצוגת התבנית. הערכים של המאפיין resizeMode הם horizontal,‏ vertical ו-none. כדי להצהיר על ווידג'ט שאפשר לשנות את הגודל שלו אופקית ואנכית, משתמשים ב-horizontal|vertical.

דוגמה

כדי להמחיש איך המאפיינים בטבלה הקודמת משפיעים על גודל הווידג'ט, נניח את המפרטים הבאים:

  • תא רשת הוא ברוחב של 30dp וגובה של 50dp.
  • מפרט המאפיינים הבא סופק:
<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 המדיניות מגדירה את התדירות שבה ה-framework של הווידג'ט מבקש עדכון מ-AppWidgetProvider באמצעות קריאה לשיטת הקריאה החוזרת (callback) של onUpdate(). לא בטוח שהעדכון יתבצע בדיוק בזמן עם הערך הזה, ואנחנו ממליצים לבצע עדכונים בתדירות נמוכה ככל האפשר – לא יותר מפעם בשעה – כדי לחסוך בסוללה. רשימת השיקולים המלאה לבחירת תקופת עדכון מתאימה מופיעה במאמר אופטימיזציות לעדכון תוכן של ווידג'טים.
initialLayout הפניה למשאב הפריסה שמגדיר את פריסת הווידג'ט.
configure המדיניות הזו מגדירה את הפעילות שמופעלת כשהמשתמש מוסיף את הווידג'ט, ומאפשרת לו להגדיר את מאפייני הווידג'ט. אפשר לקרוא את המאמר איך מאפשרים למשתמשים להגדיר ווידג'טים. החל מ-Android 12, האפליקציה יכולה לדלג על ההגדרה הראשונית. למידע נוסף, אפשר לקרוא את המאמר שימוש בהגדרות ברירת המחדל של הווידג'ט.
description התיאור שיוצג לווידג'ט בבורר הווידג'טים. הופיעה לראשונה ב-Android 12.
previewLayout (Android 12) ו-previewImage (Android 11 ומטה)
  • החל מגרסה Android 12, המאפיין previewLayout מציין תצוגה מקדימה שניתן לשנות את הגודל שלה. אתם צריכים לספק את התצוגה המקדימה כפריסה של XML שמוגדרת לגודל ברירת המחדל של הווידג'ט. באופן אידיאלי, קובץ ה-XML של הפריסה שצוין כמאפיין הזה צריך להיות זהה לקובץ ה-XML של הפריסה של הווידג'ט בפועל, עם ערכי ברירת מחדל ריאליסטיים.
  • ב-Android 11 ואילך, המאפיין previewImage מציין תצוגה מקדימה של ווידג'ט אחרי ההגדרה שלו, והמשתמש רואה אותה כשהוא בוחר את ווידג'ט האפליקציה. אם לא תספקו סמל, המשתמשים יראו במקום זאת את סמל מרכז האפליקציות של האפליקציה שלכם. השדה הזה תואם למאפיין android:previewImage ברכיב <receiver> בקובץ AndroidManifest.xml.
הערה: מומלץ לציין גם את המאפיינים previewImage וגם את המאפיינים previewLayout, כדי שהאפליקציה תוכל לעבור להשתמש ב-previewImage אם המכשיר של המשתמש לא תומך ב-previewLayout. אפשר לקרוא פרטים נוספים במאמר בנושא תאימות לאחור עם תצוגות מקדימות של ווידג'טים שניתן לשנות.
autoAdvanceViewId מזהה התצוגה של תצוגת המשנה של הווידג'ט, שמתקדמת באופן אוטומטי על ידי המארח של הווידג'ט.
widgetCategory מציין אם הווידג'ט יוצג במסך הבית (home_screen), במסך הנעילה (keyguard) או בשניהם. ב-Android מגרסה 5.0 ואילך, רק home_screen תקף.
widgetFeatures הצהרת התכונות הנתמכות בווידג'ט. לדוגמה, אם אתם רוצים שהווידג'ט ישתמש בהגדרות ברירת המחדל שלו כשמשתמש מוסיף אותו, צריך לציין גם את הדגלים configuration_optional וגם את הדגלים reconfigurable. כך אפשר לעקוף את הפעלת פעילות ההגדרה אחרי שמשתמש מוסיף את הווידג'ט. המשתמש עדיין יוכל להגדיר מחדש את הווידג'ט.

שימוש בכיתה AppWidgetProvider לטיפול בשידורים של ווידג'טים

המחלקה AppWidgetProvider מטפלת בשידורים של ווידג'טים ומעדכנת את הווידג'ט בתגובה לאירועים במחזור החיים של הווידג'ט. בקטעים הבאים מוסבר איך להצהיר על AppWidgetProvider במניפסט ואז להטמיע אותו.

הצהרה על ווידג'ט במניפסט

קודם כול, מגדירים את הכיתה AppWidgetProvider בקובץ AndroidManifest.xml של האפליקציה, כפי שמתואר בדוגמה הבאה:

<receiver android:name="ExampleAppWidgetProvider"
                 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/example_appwidget_info" />
</receiver>

אלמנט <receiver> מחייב את המאפיין android:name, שמציין את AppWidgetProvider שבו משתמש הווידג'ט. אין לייצא את הרכיב אלא אם תהליך נפרד צריך לשדר ל-AppWidgetProvider, וזה בדרך כלל לא המצב.

האלמנט <intent-filter> חייב לכלול אלמנט <action> עם המאפיין android:name. המאפיין הזה מציין שה-AppWidgetProvider מקבל את השידור של ACTION_APPWIDGET_UPDATE. זו השידור היחיד שצריך להצהיר עליו במפורש. AppWidgetManager שולח באופן אוטומטי את כל שידורי הווידג'טים האחרים אל AppWidgetProvider לפי הצורך.

הרכיב <meta-data> מציין את המשאב AppWidgetProviderInfo ונדרש לו המאפיינים הבאים:

  • android:name: מציינים את שם המטא-נתונים. משתמשים ב-android.appwidget.provider כדי לזהות את הנתונים בתור התיאור של AppWidgetProviderInfo.
  • android:resource: מציין את המיקום של המשאב AppWidgetProviderInfo.

הטמעת המחלקה AppWidgetProvider

הכיתה AppWidgetProvider היא תת-כיתה של BroadcastReceiver, ומיועדת לטיפול בשידורים של ווידג'טים. הוא מקבל רק את שידורי האירועים הרלוונטיים לווידג'ט, למשל כשהווידג'ט מתעדכן, נמחק, מופעל או מושבת. כשאירועי השידור האלה מתרחשים, מתבצעת קריאה לשיטות AppWidgetProvider הבאות:

onUpdate()
הקריאה הזו מתבצעת כדי לעדכן את הווידג'ט במרווחי זמן שמוגדרים על ידי המאפיין updatePeriodMillis בקובץ AppWidgetProviderInfo. מידע נוסף זמין בטבלה שמתארת מאפיינים נוספים של הווידג'ט בדף הזה.
השיטה הזו נקראת גם כשהמשתמש מוסיף את הווידג'ט, כדי לבצע את ההגדרות החיוניות, כמו הגדרת פונקציות לטיפול באירועים עבור אובייקטים מסוג View או הפעלת משימות לטעינת נתונים להצגה בווידג'ט. עם זאת, אם מגדירים פעילות תצורה בלי הדגל configuration_optional, השיטה הזו לא נקראת כשהמשתמש מוסיף את הווידג'ט, אבל היא כן נקראת בעדכונים הבאים. אחרי שההגדרה תושלם, פעילות ההגדרה אחראית לבצע את העדכון הראשון. מידע נוסף זמין במאמר איך לאפשר למשתמשים להגדיר ווידג'טים של אפליקציות.
הקריאה החוזרת החשובה ביותר היא onUpdate(). מידע נוסף זמין בקטע טיפול באירועים באמצעות הכיתה onUpdate() שבדף הזה.
onAppWidgetOptionsChanged()

הפונקציה הזו נקראת בפעם הראשונה שממקמים את הווידג'ט, ובכל פעם שמגדילים או מקטינים את הווידג'ט. אפשר להשתמש בקריאה החוזרת (callback) הזו כדי להציג או להסתיר תוכן בהתאם לטווחי הגודל של הווידג'ט. כדי לקבל את טווחי הגדלים – ומ-Android 12 ואילך, את רשימת הגדלים האפשריים של מופע הווידג'ט – צריך להפעיל את getAppWidgetOptions(). הפונקציה מחזירה את הערך Bundle שכולל את הפרטים הבאים:

  • OPTION_APPWIDGET_MIN_WIDTH: מכיל את הגבול התחתון של הרוחב, ביחידות dp, של מופע ווידג'ט.
  • OPTION_APPWIDGET_MIN_HEIGHT: מכיל את הגבול התחתון של הגובה, ביחידות dp, של מופע של ווידג'ט.
  • OPTION_APPWIDGET_MAX_WIDTH: מכיל את הגבול העליון של הרוחב, ביחידות dp, של מופע של ווידג'ט.
  • OPTION_APPWIDGET_MAX_HEIGHT: מכיל את הגבול העליון של הגובה, ביחידות dp, של מופע של ווידג'ט.
  • OPTION_APPWIDGET_SIZES: מכיל את רשימת הגדלים האפשריים (List<SizeF>), ביחידות dp, שהמופע של הווידג'ט יכול לקבל. הופיעה לראשונה ב-Android 12.
onDeleted(Context, int[])

הפונקציה הזו נקראת בכל פעם שווידג'ט נמחק ממארח הווידג'טים.

onEnabled(Context)

השיטה הזו נקראת כשמכונה של הווידג'ט נוצרת בפעם הראשונה. לדוגמה, אם המשתמש מוסיף שני מופעים של הווידג'ט, הפונקציה הזו תופעל רק בפעם הראשונה. אם אתם צריכים לפתוח מסד נתונים חדש או לבצע הגדרה אחרת שצריך לבצע רק פעם אחת לכל המופעים של הווידג'ט, זה המקום המתאים לעשות זאת.

onDisabled(Context)

האירוע הזה נקרא כשהמכונה האחרונה של הווידג'ט נמחקת ממארח הווידג'ט. כאן מנקים את כל העבודה שבוצעה ב-onEnabled(Context), למשל מחיקת מסד נתונים זמני.

onReceive(Context, Intent)

השיטה הזו נקראת בכל שידור וקודם לכל אחת מהשיטות הקודמות של קריאה חוזרת. בדרך כלל אין צורך להטמיע את השיטה הזו, כי הטמעת ברירת המחדל של AppWidgetProvider מסננת את כל השידורים של הווידג'ט ומפעילה את השיטות הקודמות בהתאם.

צריך להצהיר על ההטמעה של הכיתה AppWidgetProvider כמקלט שידור באמצעות הרכיב <receiver> בקובץ AndroidManifest. למידע נוסף, ראו הצהרה על ווידג'ט במניפסט.

טיפול באירועים באמצעות הכיתה onUpdate()‎

הקריאה החוזרת החשובה ביותר של AppWidgetProvider היא onUpdate(), כי היא נקראת כשמוסיפים כל ווידג'ט למארח, אלא אם משתמשים בפעילות של הגדרה ללא הדגל configuration_optional. אם הווידג'ט מקבל אירועי אינטראקציה של משתמשים, צריך לרשום את פונקציות הטיפול באירועים בקריאה החוזרת הזו. אם הווידג'ט לא יוצר קבצים זמניים או מסדי נתונים, או מבצע משימות אחרות שדורשות ניקוי, יכול להיות ש-onUpdate() היא שיטת ה-callback היחידה שצריך להגדיר.

לדוגמה, אם רוצים להשתמש בווידג'ט עם לחצן שמפעיל פעילות כשמקישים עליו, אפשר להשתמש בתהליך ההטמעה הבא של AppWidgetProvider:

Kotlin

class ExampleAppWidgetProvider : AppWidgetProvider() {

    override fun onUpdate(
            context: Context,
            appWidgetManager: AppWidgetManager,
            appWidgetIds: IntArray
    ) {
        // Perform this loop procedure for each widget that belongs to this
        // provider.
        appWidgetIds.forEach { appWidgetId ->
            // Create an Intent to launch ExampleActivity.
            val pendingIntent: PendingIntent = PendingIntent.getActivity(
                    /* context = */ context,
                    /* requestCode = */  0,
                    /* intent = */ Intent(context, ExampleActivity::class.java),
                    /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )

            // Get the layout for the widget and attach an onClick listener to
            // the button.
            val views: RemoteViews = RemoteViews(
                    context.packageName,
                    R.layout.appwidget_provider_layout
            ).apply {
                setOnClickPendingIntent(R.id.button, pendingIntent)
            }

            // Tell the AppWidgetManager to perform an update on the current
            // widget.
            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
    }
}

Java

public class ExampleAppWidgetProvider extends AppWidgetProvider {

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // Perform this loop procedure for each widget that belongs to this
        // provider.
        for (int i=0; i < appWidgetIds.length; i++) {
            int appWidgetId = appWidgetIds[i];
            // Create an Intent to launch ExampleActivity
            Intent intent = new Intent(context, ExampleActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(
                /* context = */ context,
                /* requestCode = */ 0,
                /* intent = */ intent,
                /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
            );

            // Get the layout for the widget and attach an onClick listener to
            // the button.
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current app
            // widget.
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

השדה AppWidgetProvider מגדיר רק את ה-method onUpdate(), וכך יוצר PendingIntent שמפעיל Activity ומצרף אותו ללחצן הווידג'ט באמצעות setOnClickPendingIntent(int, PendingIntent). הוא כולל לולאה שמבצעת איטרציה לכל רשומה ב-appWidgetIds, שהיא מערך של מזהים שמזהים כל ווידג'ט שנוצר על ידי הספק הזה. אם המשתמש יוצר יותר ממופעים אחדים של הווידג'ט, כולם יעודכנו בו-זמנית. עם זאת, לכל המופעים של הווידג'ט מנוהל רק לוח זמנים אחד של updatePeriodMillis. לדוגמה, אם לוח הזמנים של העדכונים מוגדר לכל שעתיים, ומודעה שנייה של הווידג'ט נוספת שעה אחרי הראשונה, שתיהן יעודכנו במסגרת התקופה שהוגדרה למודעה הראשונה, ותקופת העדכון השנייה תתעלם. שניהם מתעדכנים כל שעתיים, ולא כל שעה.

לפרטים נוספים, ראו את הכיתה לדוגמה ExampleAppWidgetProvider.java.

קבלת כוונות שידור של ווידג'ט

AppWidgetProvider היא מחלקת נוחות. אם אתם רוצים לקבל את השידור של הווידג'ט ישירות, תוכלו להטמיע BroadcastReceiver משלכם או לשנות את הפונקציה הלא חוזרת onReceive(Context,Intent). אלה כוונות החיפוש שחשוב להכיר:

יצירת הפריסה של הווידג'ט

צריך להגדיר פריסה ראשונית של הווידג'ט ב-XML ולשמור אותה בספרייה res/layout/ של הפרויקט. לפרטים נוספים אפשר לעיין בהנחיות העיצוב.

אם אתם מכירים פריסות, קל ליצור את הפריסה של הווידג'ט. עם זאת, חשוב לזכור שהפריסות של הווידג'טים מבוססות על RemoteViews, שלא תומך בכל סוגי הפריסות או הווידג'טים של התצוגה. אי אפשר להשתמש בתצוגות בהתאמה אישית או במחלקות משנה של התצוגות שנתמכות על ידי RemoteViews.

RemoteViews תומך גם ב-ViewStub, שהוא View בלתי נראה בגודל אפס שאפשר להשתמש בו כדי לנפח בזמנם משאבים של פריסה בזמן הריצה.

תמיכה בהתנהגות עם מצב

ב-Android 12 נוספה תמיכה בהתנהגות עם מצב באמצעות הרכיבים הקיימים הבאים:

הווידג'ט עדיין ללא מצב. האפליקציה צריכה לאחסן את המצב ולהירשם לאירועים של שינוי מצב.

דוגמה לווידג&#39;ט של רשימת קניות שמציג התנהגות עם מצב מסוים
איור 3. דוגמה להתנהגות עם מצב (stateful).

בדוגמת הקוד הבאה מוסבר איך מטמיעים את הרכיבים האלה.

Kotlin

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true)

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2)

// Listen for check changes. The intent has an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
        R.id.my_checkbox,
        RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent)
)

Java

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true);

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2);

// Listen for check changes. The intent has an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
    R.id.my_checkbox,
    RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent));

יש לספק שני פריסות: אחת שמטרגטת מכשירים עם Android מגרסה 12 ואילך ב-res/layout-v31, והשנייה שמטרגטת מכשירים עם Android מגרסה 11 ומטה בתיקיית ברירת המחדל res/layout.

מומלץ להטמיע פינות מעוגלות

ב-Android 12 נוספו הפרמטרים הבאים של המערכת כדי להגדיר את הרדיוס של הפינות המעוגלות של הווידג'ט:

  • system_app_widget_background_radius: הרדיוס הפינות של רקע הווידג'ט, שאף פעם לא גדול מ-28dp.

  • system_app_widget_inner_radius: רדיוס הפינה של כל תצוגה בתוך הווידג'ט. הערך הזה קטן ב-8dp בדיוק מרדיוס הרקע, כדי שהתמונה תתאים כשמשתמשים ב-8dp של ריווח.

בדוגמה הבאה מוצג ווידג'ט שמשתמש ב-system_app_widget_background_radius בפינה של הווידג'ט וב-system_app_widget_inner_radius בתצוגות בתוך הווידג'ט.

ווידג&#39;ט שבו מוצגים הרדיוס של הרקע של הווידג&#39;ט והתצוגות בתוך הווידג&#39;ט
איור 4. פינות מעוגלות.

1 פינה של הווידג'ט.

2 פינה של תצוגה בתוך הווידג'ט.

שיקולים חשובים לגבי פינות מעוגלות

  • יצרני מכשירים ומרכזי אפליקציות של צד שלישי יכולים לשנות את הפרמטר system_app_widget_background_radius כך שיהיה קטן מ-28dp. הפרמטר system_app_widget_inner_radius תמיד קטן ב-8dp מהערך של system_app_widget_background_radius.
  • אם בווידג'ט לא נעשה שימוש ב-@android:id/background או הגדרת רקע שמחלק את התוכן שלו על סמך המתאר — כאשר android:clipToOutline מוגדר ל-true — מרכז האפליקציות מזהה באופן אוטומטי את הרקע ומצמיד את הווידג'ט באמצעות מלבן עם פינות מעוגלות של עד 16dp. איך מוודאים שהווידג'ט תואם ל-Android 12

כדי שהווידג'ט יתאים לגרסאות קודמות של Android, מומלץ להגדיר מאפיינים מותאמים אישית ולהשתמש בנושא מותאם אישית כדי לשנות אותם ב-Android 12, כפי שמוצג בקובצי ה-XML לדוגמה הבאים:

/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>

/layout/my_widget_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  ...
  android:background="@drawable/my_widget_background" />