طرح بندی ویجت های انعطاف پذیر را ارائه دهید

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

این صفحه اصلاحات مربوط به اندازه ویجت و انعطاف‌پذیری بیشتر معرفی‌شده در اندروید ۱۲ (سطح API ۳۱) را شرح می‌دهد. همچنین نحوه تعیین اندازه برای ویجت شما را شرح می‌دهد.

از API های بهبود یافته برای اندازه و طرح بندی ویجت ها استفاده کنید

با شروع از اندروید ۱۲ (سطح API 31)، می‌توانید با انجام موارد زیر، همانطور که در بخش‌های بعدی توضیح داده شده است، ویژگی‌های اندازه اصلاح‌شده‌تر و طرح‌بندی‌های انعطاف‌پذیرتری ارائه دهید:

  1. محدودیت‌های اندازه ویجت اضافی را مشخص کنید.

  2. ارائه طرح‌بندی‌های واکنش‌گرا یا طرح‌بندی‌های دقیق.

در نسخه‌های قبلی اندروید، می‌توان محدوده اندازه یک ویجت را با استفاده از ویژگی‌های اضافی OPTION_APPWIDGET_MIN_WIDTH ، OPTION_APPWIDGET_MIN_HEIGHT ، OPTION_APPWIDGET_MAX_WIDTH و OPTION_APPWIDGET_MAX_HEIGHT دریافت کرد و سپس اندازه ویجت را تخمین زد، اما این منطق در همه شرایط کار نمی‌کند. برای ویجت‌هایی که اندروید ۱۲ یا بالاتر را هدف قرار می‌دهند، توصیه می‌کنیم طرح‌بندی‌های واکنش‌گرا یا دقیق ارائه دهید.

محدودیت‌های اندازه ویجت اضافی را مشخص کنید

اندروید ۱۲ رابط‌های برنامه‌نویسی کاربردی (API) اضافه کرده است که به شما امکان می‌دهد مطمئن شوید ویجت شما در دستگاه‌های مختلف با اندازه‌های مختلف صفحه نمایش، اندازه قابل اعتمادتری دارد.

علاوه بر ویژگی‌های minWidth ، minHeight ، minResizeWidth و minResizeHeight موجود، از ویژگی‌های جدید appwidget-provider زیر استفاده کنید:

  • targetCellWidth و targetCellHeight : اندازه هدف ویجت را بر اساس سلول‌های شبکه لانچر تعریف می‌کنند. در صورت تعریف، این ویژگی‌ها به جای minWidth یا minHeight استفاده می‌شوند.

  • maxResizeWidth و maxResizeHeight : حداکثر اندازه‌ای را که لانچر به کاربر اجازه می‌دهد ویجت را تغییر اندازه دهد، تعریف می‌کنند.

XML زیر نحوه استفاده از ویژگی‌های اندازه‌بندی را نشان می‌دهد.

<appwidget-provider
  ...
  android:targetCellWidth="3"
  android:targetCellHeight="2"
  android:maxResizeWidth="250dp"
  android:maxResizeHeight="110dp">
</appwidget-provider>

ارائه طرح‌بندی‌های واکنش‌گرا

اگر طرح‌بندی بسته به اندازه ویجت نیاز به تغییر دارد، توصیه می‌کنیم مجموعه کوچکی از طرح‌بندی‌ها را ایجاد کنید که هر کدام برای طیف وسیعی از اندازه‌ها معتبر باشند. اگر این امکان وجود ندارد، گزینه دیگر این است که طرح‌بندی‌ها را بر اساس اندازه دقیق ویجت در زمان اجرا ، همانطور که در این صفحه توضیح داده شده است، ارائه دهید.

این ویژگی امکان مقیاس‌بندی روان‌تر و سلامت کلی سیستم را فراهم می‌کند، زیرا سیستم لازم نیست هر بار که ویجت را در اندازه متفاوتی نمایش می‌دهد، برنامه را از حالت خواب بیدار کند.

مثال کد زیر نحوه ارائه لیستی از طرح‌بندی‌ها را نشان می‌دهد.

کاتلین

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

جاوا

@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 از ۱۶۰dp ( minResizeWidth ) × ۱۱۰dp ( minResizeHeight ) تا ۱۶۰dp × ۱۹۹dp (نقطه برش بعدی - ۱dp) پشتیبانی می‌کند.
  • tallView از ۱۶۰dp × ۲۰۰dp تا ۲۱۴dp (نقطه برش بعدی - ۱) × ۲۰۰dp پشتیبانی می‌کند.
  • wideView از ابعاد 215dp × 110dp ( minResizeHeight ) تا 250dp ( maxResizeWidth ) × 200dp ( maxResizeHeight ) پشتیبانی می‌کند.

ویجت شما باید از محدوده اندازه minResizeWidth × minResizeHeight تا maxResizeWidth × maxResizeHeight پشتیبانی کند. در این محدوده، می‌توانید نقطه برش را برای تغییر طرح‌بندی تعیین کنید.

نمونه طرح بندی واکنش گرا
شکل ۱. نمونه‌ای از یک طرح‌بندی واکنش‌گرا.

ارائه طرح‌های دقیق

اگر مجموعه کوچکی از طرح‌بندی‌های واکنش‌گرا امکان‌پذیر نیست، می‌توانید طرح‌بندی‌های متفاوتی متناسب با اندازه‌هایی که ویجت در آن‌ها نمایش داده می‌شود، ارائه دهید. این معمولاً دو اندازه برای تلفن‌ها (حالت عمودی و افقی) و چهار اندازه برای گوشی‌های تاشو است.

برای پیاده‌سازی این راهکار، برنامه شما باید مراحل زیر را انجام دهد:

  1. تابع AppWidgetProvider.onAppWidgetOptionsChanged() که هنگام تغییر مجموعه اندازه‌ها فراخوانی می‌شود، سربارگذاری کنید.

  2. فراخوانی AppWidgetManager.getAppWidgetOptions() که یک Bundle حاوی اندازه‌ها را برمی‌گرداند.

  3. به کلید AppWidgetManager.OPTION_APPWIDGET_SIZES از Bundle دسترسی پیدا کنید.

مثال کد زیر نحوه ارائه طرح‌بندی‌های دقیق را نشان می‌دهد.

کاتلین

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

جاوا

@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 - یا minWidth و minHeight برای همه نسخه‌های اندروید - را تعریف کند که حداقل فضای مصرفی پیش‌فرض را نشان می‌دهد. با این حال، وقتی کاربران یک ویجت را به صفحه اصلی خود اضافه می‌کنند، معمولاً بیشتر از حداقل عرض و ارتفاعی که شما مشخص می‌کنید، اشغال می‌کند.

صفحه‌های اصلی اندروید، شبکه‌ای از فضاهای موجود را در اختیار کاربران قرار می‌دهند که می‌توانند ویجت‌ها و آیکون‌ها را در آن قرار دهند. این شبکه می‌تواند بسته به دستگاه متفاوت باشد؛ به عنوان مثال، بسیاری از گوشی‌ها یک شبکه ۵x۴ ارائه می‌دهند و تبلت‌ها می‌توانند یک شبکه بزرگتر ارائه دهند. هنگامی که ویجت شما اضافه می‌شود، کشیده می‌شود تا حداقل تعداد سلول‌ها را به صورت افقی و عمودی اشغال کند، که برای برآورده کردن محدودیت‌های targetCellWidth و targetCellHeight در دستگاه‌هایی که اندروید ۱۲ یا بالاتر دارند، یا محدودیت‌های minWidth و minHeight در دستگاه‌هایی که اندروید ۱۱ (سطح API ۳۰) یا پایین‌تر دارند، مورد نیاز است.

هم عرض و هم ارتفاع یک سلول و هم اندازه حاشیه‌های خودکار اعمال شده برای ویجت‌ها می‌توانند در دستگاه‌های مختلف متفاوت باشند. با توجه به تعداد سلول‌های شبکه اشغال شده مورد نظر، از جدول زیر برای تخمین تقریبی حداقل ابعاد ویجت خود در یک گوشی معمولی با صفحه نمایش 5x4 استفاده کنید:

تعداد سلول‌ها (عرض × ارتفاع) اندازه موجود در حالت عمودی (dp) اندازه موجود در حالت افقی (dp)
۱x۱ ۵۷x۱۰۲dp ۱۲۷x۵۱dp
۲x۱ ۱۳۰x۱۰۲dp ۲۶۹x۵۱dp
۳x۱ ۲۰۳x۱۰۲dp ۴۱۲x۵۱dp
۴x۱ ۲۷۶x۱۰۲dp ۵۵۴x۵۱dp
۵x۱ ۳۴۹x۱۰۲dp ۶۹۷x۵۱dp
۵x۲ ۳۴۹x۲۲۰dp ۶۹۷x۱۱۷dp
۵x۳ ۳۴۹x۳۳۷dp ۶۹۷x۱۸۴dp
۵x۴ ۳۴۹x۴۵۵dp ۶۹۷x۲۵۰dp
... ... ...
ان ایکس ام (۷۳n - ۱۶) x (۱۱۸m - ۱۶) (142n - 15) x (66m - 15)

از اندازه‌های سلول در حالت عمودی برای اطلاع از مقادیری که برای ویژگی‌های minWidth ، minResizeWidth و maxResizeWidth ارائه می‌دهید، استفاده کنید. به طور مشابه، از اندازه‌های سلول در حالت افقی برای اطلاع از مقادیری که برای ویژگی‌های minHeight ، minResizeHeight و maxResizeHeight ارائه می‌دهید، استفاده کنید.

دلیل این امر این است که عرض سلول معمولاً در حالت عمودی کمتر از حالت افقی است - و به طور مشابه، ارتفاع سلول معمولاً در حالت افقی کمتر از حالت عمودی است.

برای مثال، اگر می‌خواهید عرض ویجت شما در گوگل پیکسل ۴ به اندازه یک سلول قابل تغییر اندازه باشد، باید minResizeWidth خود را حداکثر روی ۵۶dp تنظیم کنید تا مطمئن شوید مقدار ویژگی minResizeWidth کمتر از ۵۷dp است - زیرا عرض یک سلول در حالت عمودی حداقل ۵۷dp است. به طور مشابه، اگر می‌خواهید ارتفاع ویجت شما در یک سلول در همان دستگاه قابل تغییر اندازه باشد، باید minResizeHeight خود را حداکثر روی ۵۰dp تنظیم کنید تا مطمئن شوید مقدار ویژگی minResizeHeight کمتر از ۵۱dp است - زیرا ارتفاع یک سلول در حالت افقی حداقل ۵۱dp است.

هر ویجت در محدوده اندازه بین ویژگی‌های minResizeWidth / minResizeHeight و maxResizeWidth / maxResizeHeight قابل تغییر اندازه است، به این معنی که باید با هر محدوده اندازه‌ای بین آنها سازگار شود.

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

<appwidget-provider
    android:targetCellWidth="3"
    android:targetCellHeight="2"
    android:minWidth="180dp"
    android:minHeight="110dp">
</appwidget-provider>

این یعنی اندازه پیش‌فرض ویجت، سلول‌های ۳x۲ است، همانطور که توسط ویژگی‌های targetCellWidth و targetCellHeight مشخص شده است—یا ۱۸۰×۱۱۰dp، همانطور که توسط minWidth و minHeight برای دستگاه‌هایی که اندروید ۱۱ یا پایین‌تر را اجرا می‌کنند، مشخص شده است. در حالت دوم، اندازه سلول‌ها می‌تواند بسته به دستگاه متفاوت باشد.

همچنین، برای تنظیم محدوده اندازه‌های پشتیبانی‌شده توسط ویجت خود، می‌توانید ویژگی‌های زیر را تنظیم کنید:

<appwidget-provider
    android:minResizeWidth="180dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="530dp"
    android:maxResizeHeight="450dp">
</appwidget-provider>

همانطور که توسط ویژگی‌های قبلی مشخص شده است، عرض ویجت از ۱۸۰dp به ۵۳۰dp و ارتفاع آن از ۱۱۰dp به ۴۵۰dp قابل تغییر اندازه است. سپس ویجت از سلول‌های ۳x۲ به ۵x۲ قابل تغییر اندازه است، تا زمانی که شرایط زیر برقرار باشد:

کاتلین

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

جاوا

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 ) استفاده می‌شود.

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

نمونه ویجت آب و هوا در کوچکترین اندازه شبکه ۳x۲. رابط کاربری نام مکان (توکیو)، دما (۱۴ درجه) و نمادی که نشان دهنده آب و هوای نیمه ابری است را نشان می‌دهد.
شکل ۲. ۳x۲ R.layout.widget_weather_forecast_small .

نمونه ویجت آب و هوا در اندازه 4x2 «متوسط». تغییر اندازه ویجت به این روش بر اساس تمام رابط کاربری از اندازه ویجت قبلی ساخته می‌شود، و برچسب «بیشتر ابری» و پیش‌بینی دما از ساعت 4 بعد از ظهر تا 7 بعد از ظهر را اضافه می‌کند.
شکل ۳. R.layout.widget_weather_forecast_medium با ابعاد ۴x۲.

نمونه ویجت آب و هوا در اندازه 5x2 «متوسط». تغییر اندازه ویجت به این روش منجر به همان رابط کاربری با اندازه قبلی می‌شود، با این تفاوت که به اندازه یک سلول کشیده شده تا فضای افقی بیشتری را اشغال کند.
شکل ۴. ۵x۲ R.layout.widget_weather_forecast_medium .

نمونه ویجت آب و هوا در اندازه 5x3 «بزرگ». تغییر اندازه ویجت  به این ترتیب بر اساس تمام رابط کاربری از اندازه‌های ویجت قبلی ساخته می‌شود،  و یک نمای داخل ویجت اضافه می‌کند که شامل پیش‌بینی آب و هوا  سه‌شنبه و چهارشنبه است. نمادهایی که نشان‌دهنده هوای آفتابی یا بارانی  و دمای بالا و پایین برای هر روز هستند.
شکل ۵. R.layout.widget_weather_forecast_large با ابعاد ۵x۳.

نمونه ویجت آب و هوا در اندازه 5x4 «بزرگ». تغییر اندازه ویجت به این روش بر اساس تمام رابط کاربری از اندازه‌های ویجت قبلی ساخته می‌شود، و پنجشنبه و جمعه (و نمادهای مربوطه آنها که نوع آب و هوا و همچنین دمای بالا و پایین را نشان می‌دهند برای هر روز) اضافه می‌شود.
شکل ۶. R.layout.widget_weather_forecast_large با ابعاد ۵x۴.