یک ویجت ساده ایجاد کنید

روش نوشتن را امتحان کنید
Jetpack Compose ابزار رابط کاربری پیشنهادی برای اندروید است. یاد بگیرید که چگونه با استفاده از APIهای سبک Compose، ویجت بسازید.

ویجت‌های برنامه، نماهای مینیاتوری برنامه هستند که می‌توانید در برنامه‌های دیگر - مانند صفحه اصلی - جاسازی کنید و به‌روزرسانی‌های دوره‌ای را دریافت کنید. این نماها در رابط کاربری به عنوان ویجت شناخته می‌شوند و می‌توانید یکی از آنها را با یک ارائه‌دهنده ویجت برنامه (یا ارائه‌دهنده ویجت ) منتشر کنید. یک مؤلفه برنامه که ویجت‌های دیگر را در خود جای می‌دهد، میزبان ویجت برنامه (یا میزبان ویجت ) نامیده می‌شود. شکل 1 یک ویجت موسیقی نمونه را نشان می‌دهد:

نمونه ویجت موسیقی
شکل ۱. نمونه‌ای از یک ویجت موسیقی.

این سند نحوه انتشار یک ویجت با استفاده از یک ارائه‌دهنده ویجت را شرح می‌دهد. برای جزئیات بیشتر در مورد ایجاد AppWidgetHost خود برای میزبانی ویجت‌های برنامه، به ساخت میزبان ویجت مراجعه کنید.

برای اطلاعات در مورد نحوه طراحی ویجت خود، به نمای کلی ویجت‌های برنامه مراجعه کنید.

اجزای ویجت

برای ایجاد یک ویجت، به اجزای اساسی زیر نیاز دارید:

شیء AppWidgetProviderInfo
فراداده‌های یک ویجت، مانند طرح‌بندی ویجت، تعداد دفعات به‌روزرسانی و کلاس AppWidgetProvider توصیف می‌کند. AppWidgetProviderInfo در XML تعریف شده است، همانطور که در این سند توضیح داده شده است.
کلاس AppWidgetProvider
متدهای پایه‌ای را تعریف می‌کند که به شما امکان می‌دهد از طریق برنامه‌نویسی با ویجت ارتباط برقرار کنید. از طریق آن، هنگام به‌روزرسانی، فعال، غیرفعال یا حذف ویجت، اعلان‌هایی دریافت می‌کنید. شما AppWidgetProvider در مانیفست اعلام می‌کنید و سپس آن را پیاده‌سازی می‌کنید ، همانطور که در این سند توضیح داده شده است.
مشاهده طرح‌بندی
طرح اولیه ویجت را تعریف می‌کند. این طرح در XML تعریف شده است، همانطور که در این سند توضیح داده شده است.

شکل ۲ نشان می‌دهد که چگونه این اجزا در جریان کلی پردازش ویجت برنامه قرار می‌گیرند.

جریان پردازش ویجت برنامه
شکل ۲. جریان پردازش ویجت برنامه.

اگر ویجت شما نیاز به پیکربندی کاربر دارد، فعالیت پیکربندی ویجت برنامه را پیاده‌سازی کنید. این فعالیت به کاربران امکان می‌دهد تنظیمات ویجت را تغییر دهند - برای مثال، منطقه زمانی برای ویجت ساعت.

ما همچنین بهبودهای زیر را توصیه می‌کنیم: طرح‌بندی‌های انعطاف‌پذیر ویجت ، بهبودهای متفرقه ، ویجت‌های پیشرفته ، ویجت‌های مجموعه و ساخت یک میزبان ویجت .

اعلان فایل 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 (اندروید ۱۲)، minWidth و minHeight
  • از اندروید ۱۲ به بعد، ویژگی‌های targetCellWidth و targetCellHeight اندازه پیش‌فرض ویجت را بر حسب سلول‌های شبکه‌ای مشخص می‌کنند. این ویژگی‌ها در اندروید ۱۱ و پایین‌تر نادیده گرفته می‌شوند و اگر صفحه اصلی از طرح‌بندی مبتنی بر شبکه پشتیبانی نکند، می‌توان آن‌ها را نادیده گرفت.
  • ویژگی‌های minWidth و minHeight اندازه پیش‌فرض ویجت را بر حسب dp مشخص می‌کنند. اگر مقادیر مربوط به حداقل عرض یا ارتفاع ویجت با ابعاد سلول‌ها مطابقت نداشته باشند، مقادیر به نزدیکترین اندازه سلول گرد می‌شوند.
توصیه می‌کنیم هر دو مجموعه از ویژگی‌ها - targetCellWidth و targetCellHeight و minWidth و minHeight - را مشخص کنید تا در صورت عدم پشتیبانی دستگاه کاربر targetCellWidth و targetCellHeight ، برنامه شما بتواند به استفاده minWidth و minHeight بازگردد. در صورت پشتیبانی، ویژگی‌های targetCellWidth و targetCellHeight بر ویژگی‌های minWidth و minHeight اولویت دارند.
minResizeWidth و minResizeHeight حداقل اندازه مطلق ویجت را مشخص کنید. این مقادیر، اندازه‌ای را مشخص می‌کنند که ویجت در آن ناخوانا یا غیرقابل استفاده است. استفاده از این ویژگی‌ها به کاربر اجازه می‌دهد تا ویجت را به اندازه‌ای کوچکتر از اندازه پیش‌فرض ویجت تغییر اندازه دهد. ویژگی minResizeWidth اگر بزرگتر از minWidth باشد یا تغییر اندازه افقی فعال نباشد، نادیده گرفته می‌شود. به resizeMode مراجعه کنید. به همین ترتیب، ویژگی minResizeHeight اگر بزرگتر از minHeight باشد یا تغییر اندازه عمودی فعال نباشد، نادیده گرفته می‌شود.
maxResizeWidth و maxResizeHeight حداکثر اندازه توصیه‌شده برای ویجت را مشخص کنید. اگر مقادیر مضربی از ابعاد سلول‌های شبکه نباشند، به نزدیکترین اندازه سلول گرد می‌شوند. اگر ویژگی maxResizeWidth کوچکتر از minWidth باشد یا تغییر اندازه افقی فعال نباشد، نادیده گرفته می‌شود. به resizeMode مراجعه کنید. به همین ترتیب، اگر ویژگی maxResizeHeight بزرگتر از minHeight باشد یا تغییر اندازه عمودی فعال نباشد، نادیده گرفته می‌شود. در اندروید ۱۲ معرفی شده است.
resizeMode قوانینی را مشخص می‌کند که بر اساس آنها می‌توان اندازه یک ویجت را تغییر داد. می‌توانید از این ویژگی برای تغییر اندازه ویجت‌های صفحه اصلی به صورت افقی، عمودی یا روی هر دو محور استفاده کنید. کاربران یک ویجت را لمس کرده و نگه می‌دارند تا دستگیره‌های تغییر اندازه آن نمایش داده شود، سپس دستگیره‌های افقی یا عمودی را می‌کشند تا اندازه آن را روی شبکه طرح تغییر دهند. مقادیر ویژگی 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" />

شروع با اندروید ۱۲:

از ویژگی‌های targetCellWidth و targetCellHeight به عنوان اندازه پیش‌فرض ویجت استفاده کنید.

اندازه ویجت به طور پیش‌فرض ۲x۲ است. می‌توان آن را به ۲x۱ یا تا ۴x۳ تغییر داد.

اندروید ۱۱ و پایین‌تر:

از ویژگی‌های minWidth و minHeight برای محاسبه اندازه پیش‌فرض ویجت استفاده کنید.

عرض پیش‌فرض = Math.ceil(80 / 30) = 3

ارتفاع پیش‌فرض = Math.ceil(80 / 50) = 2

اندازه ویجت به طور پیش‌فرض ۳x۲ است. می‌توان آن را به ۲x۱ یا تا تمام صفحه تغییر اندازه داد.

ویژگی‌های ویجت اضافی

جدول زیر ویژگی‌های <appwidget-provider> مربوط به ویژگی‌هایی غیر از اندازه ویجت را شرح می‌دهد.

ویژگی‌ها و توضیحات
updatePeriodMillis تعریف می‌کند که فریم‌ورک ویجت با فراخوانی متد onUpdate() چند وقت یکبار از AppWidgetProvider درخواست به‌روزرسانی می‌کند. با این مقدار، تضمینی وجود ندارد که به‌روزرسانی دقیقاً سر وقت انجام شود و توصیه می‌کنیم برای صرفه‌جویی در مصرف باتری، به‌روزرسانی را تا حد امکان به ندرت - حداکثر هر یک ساعت یک بار - انجام دهید. برای مشاهده لیست کامل ملاحظات برای انتخاب یک دوره به‌روزرسانی مناسب، به بهینه‌سازی‌ها برای به‌روزرسانی محتوای ویجت مراجعه کنید.
initialLayout به منبع طرح‌بندی که طرح‌بندی ویجت را تعریف می‌کند، اشاره دارد.
configure فعالیتی را تعریف می‌کند که هنگام افزودن ویجت توسط کاربر، اجرا می‌شود و به آنها اجازه می‌دهد ویژگی‌های ویجت را پیکربندی کنند. به بخش «فعال کردن کاربران برای پیکربندی ویجت‌ها» مراجعه کنید. از اندروید ۱۲ به بعد، برنامه شما می‌تواند از پیکربندی اولیه صرف نظر کند. برای جزئیات بیشتر به بخش «استفاده از پیکربندی پیش‌فرض ویجت» مراجعه کنید.
description توضیحی را برای انتخابگر ویجت جهت نمایش ویجت شما مشخص می‌کند. معرفی شده در اندروید ۱۲.
previewLayout (اندروید ۱۲) و previewImage (اندروید ۱۱ و پایین‌تر)
  • از اندروید ۱۲ به بعد، ویژگی previewLayout یک پیش‌نمایش مقیاس‌پذیر را مشخص می‌کند که شما آن را به عنوان یک طرح‌بندی XML که روی اندازه پیش‌فرض ویجت تنظیم شده است، ارائه می‌دهید. در حالت ایده‌آل، XML طرح‌بندی مشخص شده به عنوان این ویژگی، همان XML طرح‌بندی ویجت واقعی با مقادیر پیش‌فرض واقع‌بینانه است.
  • در اندروید ۱۱ یا پایین‌تر، ویژگی previewImage پیش‌نمایشی از ظاهر ویجت پس از پیکربندی آن را مشخص می‌کند که کاربر هنگام انتخاب ویجت برنامه آن را می‌بیند. اگر این ویژگی ارائه نشود، کاربر در عوض آیکون لانچر برنامه شما را می‌بیند. این فیلد با ویژگی android:previewImage در عنصر <receiver> در فایل AndroidManifest.xml مطابقت دارد.
نکته: توصیه می‌کنیم هر دو ویژگی previewImage و previewLayout را مشخص کنید تا در صورت عدم پشتیبانی دستگاه کاربر previewLayout ، برنامه شما بتواند به استفاده previewImage بازگردد. برای جزئیات بیشتر، به بخش سازگاری معکوس با پیش‌نمایش‌های ویجت مقیاس‌پذیر مراجعه کنید.
autoAdvanceViewId شناسه نمای زیرنمای ویجت را که توسط میزبان ویجت به صورت خودکار ارتقا داده می‌شود، مشخص می‌کند.
widgetCategory مشخص می‌کند که آیا ویجت شما می‌تواند در صفحه اصلی ( home_screen )، صفحه قفل ( keyguard ) یا هر دو نمایش داده شود یا خیر. برای اندروید ۵.۰ و بالاتر، فقط 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 فراخوانی می‌شود. برای اطلاعات بیشتر به جدول توصیف ویژگی‌های اضافی ویجت در این صفحه مراجعه کنید.
این متد همچنین زمانی که کاربر ویجت را اضافه می‌کند، فراخوانی می‌شود، بنابراین تنظیمات ضروری مانند تعریف event handlerها برای اشیاء View یا شروع کارها برای بارگذاری داده‌ها جهت نمایش در ویجت را انجام می‌دهد. با این حال، اگر یک activity پیکربندی را بدون پرچم configuration_optional اعلام کنید، این متد زمانی که کاربر widget را اضافه می‌کند فراخوانی نمی‌شود ، اما برای به‌روزرسانی‌های بعدی فراخوانی می‌شود . این مسئولیت activity پیکربندی است که اولین به‌روزرسانی را پس از تکمیل پیکربندی انجام دهد. برای اطلاعات بیشتر به Enable users to configure app widgets مراجعه کنید.
مهم‌ترین تابع فراخوانی onUpdate() است. برای اطلاعات بیشتر به بخش مدیریت رویدادها با کلاس onUpdate() در این صفحه مراجعه کنید.
onAppWidgetOptionsChanged()

این تابع هنگام اولین قرارگیری ویجت و هر زمان که اندازه ویجت تغییر می‌کند، فراخوانی می‌شود. از این تابع فراخوانی برای نمایش یا پنهان کردن محتوا بر اساس محدوده اندازه ویجت استفاده کنید. محدوده اندازه‌ها - و از اندروید ۱۲ به بعد، لیست اندازه‌های ممکنی که یک نمونه ویجت می‌تواند بگیرد - را با فراخوانی 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 است که یک نمونه ویجت می‌تواند داشته باشد. در اندروید ۱۲ معرفی شده است.
onDeleted(Context, int[])

این هر بار که یک ویجت از میزبان ویجت حذف می‌شود، فراخوانی می‌شود.

onEnabled(Context)

این متد زمانی فراخوانی می‌شود که یک نمونه از ویجت برای اولین بار ایجاد می‌شود. برای مثال، اگر کاربر دو نمونه از ویجت شما اضافه کند، این متد فقط برای اولین بار فراخوانی می‌شود. اگر نیاز به باز کردن یک پایگاه داده جدید یا انجام تنظیمات دیگری دارید که فقط باید یک بار برای همه نمونه‌های ویجت اتفاق بیفتد، اینجا مکان مناسبی برای انجام این کار است.

onDisabled(Context)

این تابع زمانی فراخوانی می‌شود که آخرین نمونه ویجت شما از میزبان ویجت حذف شود. در اینجا هر کاری که در onEnabled(Context) انجام شده است، مانند حذف یک پایگاه داده موقت، پاک می‌شود.

onReceive(Context, Intent)

این برای هر پخش و قبل از هر یک از متدهای فراخوانی قبلی فراخوانی می‌شود. معمولاً نیازی به پیاده‌سازی این متد ندارید، زیرا پیاده‌سازی پیش‌فرض AppWidgetProvider تمام پخش‌های ویجت را فیلتر کرده و متدهای قبلی را در صورت لزوم فراخوانی می‌کند.

شما باید پیاده‌سازی کلاس AppWidgetProvider خود را به عنوان یک گیرنده‌ی اعلان اعلان کنید. برای اطلاعات بیشتر به بخش <receiver> ویجت در مانیفست AndroidManifest این صفحه مراجعه کنید.

مدیریت رویدادها با کلاس onUpdate()

مهم‌ترین تابع فراخوانی AppWidgetProvider onUpdate() است، زیرا وقتی هر ویجت به یک میزبان اضافه می‌شود، فراخوانی می‌شود، مگر اینکه از یک فعالیت پیکربندی بدون پرچم configuration_optional استفاده کنید. اگر ویجت شما هرگونه رویداد تعامل با کاربر را می‌پذیرد، در این تابع فراخوانی، کنترل‌کننده‌های رویداد را ثبت کنید. اگر ویجت شما فایل‌های موقت یا پایگاه‌های داده ایجاد نمی‌کند، یا کار دیگری که نیاز به پاکسازی دارد انجام نمی‌دهد، در این صورت onUpdate() ممکن است تنها تابع فراخوانی باشد که باید تعریف کنید.

برای مثال، اگر ویجتی می‌خواهید که دکمه‌ای داشته باشد که با لمس آن، یک اکتیویتی اجرا شود، می‌توانید از پیاده‌سازی زیر از AppWidgetProvider استفاده کنید:

کاتلین

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)
        }
    }
}

جاوا

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 فقط متد onUpdate() را تعریف می‌کند و از آن برای ایجاد یک PendingIntent استفاده می‌کند که یک Activity راه‌اندازی کرده و آن را با استفاده از setOnClickPendingIntent(int, PendingIntent) به دکمه ویجت متصل می‌کند. این شامل حلقه‌ای است که از طریق هر ورودی در appWidgetIds تکرار می‌شود، که آرایه‌ای از شناسه‌ها است که هر ویجت ایجاد شده توسط این ارائه دهنده را شناسایی می‌کند. اگر کاربر بیش از یک نمونه از ویجت ایجاد کند، همه آنها به طور همزمان به‌روزرسانی می‌شوند. با این حال، فقط یک برنامه updatePeriodMillis برای همه نمونه‌های ویجت مدیریت می‌شود. به عنوان مثال، اگر برنامه به‌روزرسانی هر دو ساعت تعریف شده باشد و نمونه دوم ویجت یک ساعت پس از نمونه اول اضافه شود، هر دو در دوره تعریف شده توسط نمونه اول به‌روزرسانی می‌شوند و دوره به‌روزرسانی دوم نادیده گرفته می‌شود. هر دو هر دو ساعت به‌روزرسانی می‌شوند، نه هر ساعت.

برای جزئیات بیشتر به کلاس نمونه ExampleAppWidgetProvider.java مراجعه کنید.

دریافت اهداف پخش ویجت

AppWidgetProvider یک کلاس کمکی است. اگر می‌خواهید اعلان‌های ویجت را مستقیماً دریافت کنید، می‌توانید BroadcastReceiver خود را پیاده‌سازی کنید یا تابع فراخوانی onReceive(Context,Intent) بازنویسی کنید. Intentهایی که باید به آنها توجه کنید عبارتند از:

طرح بندی ویجت را ایجاد کنید

شما باید یک طرح اولیه برای ویجت خود در XML تعریف کنید و آن را در پوشه res/layout/ پروژه ذخیره کنید. برای جزئیات بیشتر به دستورالعمل‌های طراحی مراجعه کنید.

اگر با طرح‌بندی‌ها آشنا باشید، ایجاد طرح‌بندی ویجت ساده است. با این حال، توجه داشته باشید که طرح‌بندی‌های ویجت مبتنی بر RemoteViews هستند که از هر نوع طرح‌بندی یا ویجت نمایشی پشتیبانی نمی‌کند. شما نمی‌توانید از نماهای سفارشی یا زیرکلاس‌های نماهایی که توسط RemoteViews پشتیبانی می‌شوند، استفاده کنید.

RemoteViews همچنین از ViewStub پشتیبانی می‌کند، که یک View نامرئی و با اندازه صفر است که می‌توانید از آن برای افزایش تدریجی منابع طرح‌بندی در زمان اجرا استفاده کنید.

پشتیبانی از رفتار حالت‌مند

اندروید ۱۲ با استفاده از اجزای موجود زیر، پشتیبانی از رفتار stateful را اضافه می‌کند:

ویجت هنوز بدون وضعیت است. برنامه شما باید وضعیت را ذخیره کند و برای رویدادهای تغییر وضعیت ثبت نام کند.

مثالی از ویجت لیست خرید که رفتار stateful را نشان می‌دهد
شکل ۳. نمونه‌ای از رفتار مبتنی بر حالت.

نمونه کد زیر نحوه پیاده‌سازی این اجزا را نشان می‌دهد.

کاتلین

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

جاوا

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

دو طرح‌بندی ارائه دهید: یکی دستگاه‌هایی را هدف قرار می‌دهد که اندروید ۱۲ یا بالاتر را در res/layout-v31 اجرا می‌کنند و دیگری دستگاه‌های اندروید ۱۱ یا پایین‌تر را که در پوشه پیش‌فرض res/layout قرار دارند، هدف قرار می‌دهد.

پیاده‌سازی گوشه‌های گرد

اندروید ۱۲ پارامترهای سیستمی زیر را برای تنظیم شعاع گوشه‌های گرد ویجت شما معرفی می‌کند:

  • system_app_widget_background_radius : شعاع گوشه پس‌زمینه ویجت که هرگز بزرگتر از ۲۸ dp نیست.

  • شعاع داخلی، که می‌تواند از شعاع خارجی و فاصله‌گذاری محاسبه شود. به قطعه کد زیر مراجعه کنید:

    /**
     * Applies corner radius for views that are visually positioned [widgetPadding]dp inside of the
     * widget background.
     */
    @Composable
    fun GlanceModifier.appWidgetInnerCornerRadius(widgetPadding: Dp): GlanceModifier {
    
        if (Build.VERSION.SDK_INT < 31) {
            return this
        }
    
        val resources = LocalContext.current.resources
        // get dimension in float (without rounding).
        val px = resources.getDimension(android.R.dimen.system_app_widget_background_radius)
        val widgetBackgroundRadiusDpValue = px / resources.displayMetrics.density
        if (widgetBackgroundRadiusDpValue < widgetPadding.value) {
            return this
        }
        return this.cornerRadius(Dp(widgetBackgroundRadiusDpValue - widgetPadding.value))
    }

برای محاسبه شعاع مناسب برای محتوای داخلی ویجت خود، از فرمول زیر استفاده کنید: systemRadiusValue - widgetPadding

ویجت‌هایی که محتوای خود را به شکل‌های غیرمستطیلی برش می‌دهند، باید از @android:id/background ‎ به عنوان شناسه نمای پس‌زمینه‌ای که android:clipToOutline آن روی true تنظیم شده است، استفاده کنند.

نکات مهم در مورد گوشه‌های گرد

  • لانچرهای شخص ثالث و تولیدکنندگان دستگاه می‌توانند پارامتر system_app_widget_background_radius را طوری تغییر دهند که کوچکتر از ۲۸ dp باشد.
  • اگر ویجت شما از @android:id/background ‎ استفاده نمی‌کند یا پس‌زمینه‌ای تعریف نمی‌کند که محتوای آن را بر اساس طرح کلی برش دهد - با android:clipToOutline که روی true تنظیم شده باشد - لانچر به طور خودکار پس‌زمینه را شناسایی کرده و ویجت را با استفاده از یک مستطیل با گوشه‌های گرد که با شعاع سیستم تنظیم شده است، برش می‌دهد.

  • شکل‌های غیرمستطیلی باید درون محفظه تغییر اندازه مستطیلی گرد خود قرار گیرند تا بریده نشوند.

  • از اندروید ۱۶ به بعد، مقدار سیستم AOSP برای system_app_widget_background_radius 24dp است. لانچرها و تولیدکنندگان دستگاه ممکن است ویجت را به system_app_widget_background_radius متصل کنند.

  • محتوای داخلی یک ویجت باید دارای فاصله‌گذاری (padding) کافی برای پشتیبانی از مقادیر شعاع system_app_widget_background_radius تا 28dp باشد تا از بریده شدن محتوا توسط گوشه‌های گرد جلوگیری شود.

برای سازگاری ویجت با نسخه‌های قبلی اندروید، توصیه می‌کنیم ویژگی‌های سفارشی تعریف کنید و از یک تم سفارشی برای لغو آنها برای اندروید ۱۲ استفاده کنید، همانطور که در فایل‌های 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" />