کانال بله, جهت پشتیبانی و اطلاع رسانی کانال بله, جهت پشتیبانی و اطلاع رسانی
عضویت

ابزارک های رابط کاربری در صفحه اصلی

آموزش حاضر نحوه ی ایجادwidget ها در صفحه ی اصلی دستگاه اندروید را شرح می دهد.

شرح مفهوم Widgetدر اندروید

مروری بر AppWidgets

Widget ها اپلیکیشن های کوچک هستند و به راحتی بر روی یک میزبان که اغلب home screen یا lock screen (صفحه ی قفل نمایشگر) دستگاه اندروید هست، قابل جایگذاری می باشد. می توانید به widget ها به دید یک نمونه ی کوچک از کل اپلیکیشن و قابلیت های آن که از طریق صفحه ی اصلی دستگاه قابل دسترسی می باشد، نگاه کرد.

یک widget به عنوان بخشی از فرایند میزبان خود اجرا می شود. این امر لازمه ی آن است که widget از مجوزهای اپلیکیشن میزبان خود برخوردار بوده و آن ها را حفظ کنند.

Widget برای ساخت ظاهر و UI خود در صفحه اصلی دستگاه از کلاس RemoteViews استفاده می کند. کلاس RemoteView این قابلیت را دارد که با همان مجوزهای اپلیکیشن اصلی توسط فرایند دیگر راه اندازی شود. در واقع Widget ها با بهره گیری از این کلاس قادرند با مجوزهای اپلیکیشن اصلی که ابزارک ها به آن متصل هستند، اجرا شوند.

Widget ها برای ساخت ظاهر (UI) خود از broadcast receiver نیز کمک می گیرند. در حقیقت receiver یک آبجکت از جنس RemoteViews را با محتوای layout مربوطه پر می کند (آن را در این آبجکت inflate می کند). آبجکت نام برده سپس به اندروید تحویل داده شده و از آنجا در قالب widget مستقر در صفحه ی اصلی (home screen) برای کاربر به نمایش در می آید.

مراحل ساخت یک widget

  • یک فایل layout تعریف نمایید.
  • یک فایل XML (AppWidgetProviderInfo) ایجاد نموده که property ها و خصوصیت های widget همچون اندازه، زمان و دفعات تکرار بروز رسانی اطلاعات را مشخص کند.
  • یک BroadcastReceiver ایجاد کنید که در ساخت رابط کاربری و ظاهر widget مورد استفاده قرار می گیرد.
  • تنظیمات و کانفیگ Widget را در فایل AndroidManifest.xml درج نمایید.
  • در صورت تمایل می توانید یک activity جهت انجام تنظیمات (configuration activity) تعریف نمایید که به مجرد اضافه شدن نمونه ای از widget به میزبان (widget host همچون صفحه ی اصلی)، صدا خورده می شود.

اندازه ی widget

قبل از ویرایش 3.1 اندروید، یک widget همیشه تعداد مشخصی خانه (cell) را در صفحه ی اصلی دستگاه به خود اختصاص می داد. هر خانه معمولا به اندازه ی یک آیکون فضا فراهم می کند. برای محاسبه ی میزان فضای مورد نیاز یک widget می بایست از فرمول رو به رو استفاده کنید: ((Number of columns / rows) * 74) – 2 . این اندازه بر حسب واحد dip (device independent pixel) محاسبه می شود. مقدار 2- برای اجتناب از خطاهای مربوط به گرد کردن لحاظ شده است.

از ویرایش 3.1 به بعد اندروید، کاربران این اجازه را دارند که اندازه ی widget را مطابق نیاز تنظیم نمایند. جهت فعال سازی این قابلیت، می توانید مقدار android:resizeMode را در فایل تنظیمات XML برای این widget برابر ="horizontal|vertical" قرار دهید.

ایجاد Broadcast receiver برای widget

ساخت و تنظیم widget

به منظور تعریف widget، لازم است یک broadcast receiver با intent filter ای که المان action آن بر روی android.appwidget.action.APPWIDGET_UPDATEتنظیم شده باشد، ایجاد نمایید.




       


می توان به receiver یک label و آیکون تخصیص داد. این دو در لیست widget های موجود در launcher اندروید و به عنوان فایلی که با کلیک بر روی آن اپلیکیشن اجرا می شود، لیست می گردد.

می توانید با مقداردهی android:name="android.appwidget.provider، برای widget مورد نظر meta-data تعریف نمایید. فایل تنظیماتی که meta data به آن اشاره می کند، تمامی تنظیمات و کانفیگ widget مورد نظر را شامل می شود. این تنظیمات می تواند مربوط به تناوب و دفعات بروز رسانی UI، اندازه و layout (ظاهر، چیدمان کلی) اولیه ی widget باشد.




View ها و layout های موجود و قابل استفاده

Widget در استفاده از کلاس های View با محدودیت مواجه است. برای تنظیم چیدمان و طرح کلی (layout) می توانید از FrameLayout، LinearLayout و RelativeLayout استفاده نمایید. به عنوان view ها می توانید از AnalogClock، Button، Chromometer، ImageButton، ImageView، ProgressBar و TextView استفاده کنید.

از ویرایش 3.0 اندروید به بعد view های بیشتری در اختیار توسعه دهنده قرار گرفته است که از میان آن ها می توان از GridView، ListView، StackView، ViewFlipper و AdapterViewFlipper نام برد.

برای استفاده از این adapter view ها (کلاس های مشتق شده از AdapterView) شما ملزوم به تعریف یک collection view widget هستید.

تنها پل ارتباطی و وسیله ی تعامل با view های یک widget از طریق event یا رخداد onClickListener می باشد. این event را می توان در widget ثبت نموده و به محض تعامل کاربر با widget، اتفاق افتادن آن را اعلان کرد.

AppWidgetProvider

پیاده سازی کلاس BroadcastReceiver معمولا اعضا و توابع کلاس AppWidgetProvider را به ارث می برد.

کلاس AppWidgetProvider متد onReceive() را پیاده سازی کرده، اطلاعات لازم را استخراج می کند و در نهایت متدهای مدیریت چرخه ی حیات widget را صدا می زند.

از آنجایی که می توانید چندین نمونه از یک widget را به صفحه ی اصلی (home screen) اضافه نمایید، متدهای مربوط به مدیریت چرخه ی حیات widget به دو دسته تقسیم می شوند: 1. متدهایی که تنها برای اولین نمونه اضافه/حذف شده فراخوانده می شوند 2. متدهایی که به ازای هر نمونه از widget صدا خورده می شوند.

متد
شرح
onEnabled()
زمانی فراخوانی می گردد که نمونه ی widget برای اولین بار به home screen اضافه می شود.
onDisabled()
تنها یکبار زمانی که آخرین نمونه ی widget از صفحه ی اصلی حذف می شود، فراخوانی می گردد.
onUpdate()
این متد به ازای هر بار بروز رسانی widget فراخوانی می شود. متد مذکور شناسه های appWidgetId آن widget هایی که باید با اطلاعات جدید بروز آوری شوند را به عنوان پارامتر ورودی در قالب آرایه دریافت می کند. توجه داشته باشید که این می تواند تمامی نمونه های AppWidget کلاس Provider را شامل شود یا صرفا زیر مجموعه ای از آن را دربرگیرد.
onDeleted()
با فراخوانی این متد نمونه ی widget از صفحه ی اصلی (widget instance) حذف می گردد.

Receiver و پردازش ناهمزمان

Widget همان محدودیت هایی را در زمان اجرای برنامه دارد که یک broadcast receiver معمولی با آن مواجه می شود. برای مثال می بایست پردازش خود را نهایتا در عرض 5 ثانیه به اتمام برساند.

یک receiver می بایست عملیات طولانی در سرویس انجام داده و سپس widget ها را از آن سرویس بروز رسانی کند.

بروز رسانی widget

یک widget داده های جدید خود را بر اساس یک جدول زمانی و در فواصل زمانی مشخص دریافت می کند. برای بروز رسانی یک widget دو روش وجود دارد: 1. یکی مبتنی بر فایل تنظیمات XML بوده 2. دیگری توسط سرویس AlarmManager اندروید صورت می گیرد.

در فایل تنظیمات widget، شما می توانید یک فاصله ی زمانی مشخص تعیین نمایید که بروزرسانی بر اساس آن صورت گیرد. سیستم پس از گذشت این زمان مشخص بیدار شده و broadcast receiver را جهت بروز رسانی widget با داده های جدید فراخوانی می کند. کم ترین فاصله ی زمانی که آپدیت بر اساس آن رخ می دهد، حدودا 1800000 میلی ثانیه معادل 30 دقیقه می باشد. بدین معنی که widget هر 30 دقیقه آپدیت می شود.

AlarmManager این امکان را برای شما فراهم می کند تا در استفاده از منابع صرفه جویی نموده و widget خود را تعداد دفعات بیشتری بروز رسانی نمایید. برای استفاده از این روش، ابتدا یک سرویس تعریف نموده و سپس با استفاده از کلاس AlarmManager آن را طوری زمان بندی می کنید که در فواص زمانی معین اجرا شود. این سرویس متعاقبا widget را به طور مرتب بروز رسانی می کند.

توجه داشته باشید که بروز رسانی در فواصل زمانی بیشتر (با تعداد دفعات بروز رسانی بیشتر) ناگذیر سیستم را از حالت صرفه جویی در مصرف باتری خارج ساخته و در نتیجه widget مورد نظر انرژی بیشتری را مصرف خواهد نمود.

تمرین: پیاده سازی widget و بروز رسانی آن در فواصل زمانی معین

هدف تمرین

در زیر widget ای خواهید ساخت که یک عدد تصادفی را در UI نمایش می دهد. این عدد تصادفی هر 30 دقیقه یکبار بروز رسانی می شود. سپس یک onClickListener ثبت می کنید که با کلیک کاربر بر روی آن، بروز رسانی می شود.

Widget در نهایت ظاهری مشابه زیر خواهید داشت.

ساخت ویجت،ساخت ابزارک

ساخت پروژه و پیاده سازی widget

یک پروژه ی جدید اندروید به نام de.vogella.android.widget.example ایجاد نموده سپس یک activity جدید در پکیج de.vogella.android.widget.example ایجاد کنید.

یک فایل جدید به نام myshape.xml در پوشه ی /res/drawable ایجاد نمایید. این فایل در واقع drawable یا فایل تصویری ترسیم شونده ای که به عنوان پس زمینه در widget مورد استفاده قرار می گیرد را تعریف می نماید.







فایل widget_layout.xml با محتویات زیر را تحت پوشه ی res/layout ایجاد نمایید.




    

یک فایل محتوا (resource) دیگر به نام widget_info.xml با کلیک راست بر روی پوشه ی res ایجاد نموده و سپس مسیر رو به رو را طی نمایید: New ▸ Android resource file.

پیاده سازی ویجت



یک کلاس receiver با پیاده سازی زیر ایجاد نمایید که با هر بار بروز رسانی widget صدا خورده می شود.

package de.vogella.android.widget.example;
import java.util.Random;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
public class MyWidgetProvider extends AppWidgetProvider {
        private static final String ACTION_CLICK = "ACTION_CLICK";
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                        int[] appWidgetIds) {
                // Get all ids
                ComponentName thisWidget = new ComponentName(context,
                                MyWidgetProvider.class);
                int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
                for (int widgetId : allWidgetIds) {
                        // create some random data
                        int number = (new Random().nextInt(100));
                        RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
                                        R.layout.widget_layout);
                        Log.w("WidgetExample", String.valueOf(number));
                        // Set the text
                        remoteViews.setTextViewText(R.id.update, String.valueOf(number));
                        // Register an onClickListener
                        Intent intent = new Intent(context, MyWidgetProvider.class);                        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);                       intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
                        PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
                                        0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
                        remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
                        appWidgetManager.updateAppWidget(widgetId, remoteViews);
                }
        }
}

فایل AndroidManifest.xml را باز نموده و سپس widget خود را به صورت نمایش داده شده در کد زیر ثبت و تعریف نمایید.







            

        
    


این attribute اعلان می کند که AppWidgetProvider برادکست ACTION_APPWIDGET_UPDATE را پذیرفته و نیز metadata مربوط به widget را مشخص می کند.

تست اپلیکیشن

اپلیکیشن خود را بر روی دستگاه اندروید نصب (deploy) نمایید. پس از نصب اپلیکیشن، با استفاده از launcher اندروید widget را بر روی صفحه ی اصلی دستگاه نصب و آن را تست کنید.

تست پیاده سازی ویجت

Collection View Widget

پیش از هر چیز لازم است درباره ی collection widget توضیح مختصری را در اختیار شما قرار دهیم. Collection widget ویژه ی نمایش مجموعه ای از المان های یکسان مورد استفاده قرار می گیرد. برای مثال می توان به تعدادی عکس از اپلیکیشن gallery، تعدادی مقاله از اپلیکیشن خبرخوان یا مجموعه ای از پیغام/ایمیل ها از یک اپلیکیشن ارتباطات سخن گفت. Collection widget معمولا به دو منظور مورد استفاده قرار می گیرد: 1. پیمایش در مجموعه ای از آیتم ها 2. باز کردن آیتمی از مجموعه جهت مشاهده ی صفحه ی اصلی و جزئیات آن. Collection widget دارای نوار اسکرول در کناره ی سمت راست بوده که به شما اجازه ی پیمایش به صورت عمودی را می دهد.

collection view widget به شما این امکان را می دهد تا از کلاس های ListView (جهت پیاده سازی لیست ساده)، stackview، GridView (لیستی مانند جدول خانه بندی شده) در بستر widget استفاده نمایید.

برای پیاده سازی collection view widget شما به دو فایل layout احتیاج دارید: 1. یکی برای widget 2. دیگری برای هر آیتم در widget collection.

آیتم های widget توسط نمونه ای از RemoteViewsFactory ساخته شده و با کلاس factory پر می شوند (Factory class = در مفهوم شی گرایی، آبجکتی که برای ساخت آبجکت دیگر تعبیه شده در اصطلاح factory خوانده می شود).

کلاس factory به عنوان یک الگو برای ساخت آبجکت های دیگر ایفای نقش می کند. این کلاس در اصل توسط یک سرویس اندروید که خود اعضا و توابع کلاس RemoteViewsFactory را به ارث می برد، در اختیار توسعه دهنده قرار می گیرد. لازم به ذکر است که سرویس مزبور برای فعالیت به تنظیم مجوز android.permission.BIND_REMOTEVIEWS در فایل تنظیمات اپلیکیشن نیاز دارد.

جهت متصل کردن view های خود به سرویس، لازم است متد onUpdate() را در پیاده سازی widget بکار ببرید.

لازم است یک intent تعریف نموده که به سرویس مورد نظر دسترسی دارد ( به آن اشاره داشته) و بعد متد setRemoteAdapter را در سطح کلاس RemoteViews بکار ببرید.

Intent intent = new Intent(context, YourRemoteViewsService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
views.setRemoteAdapter(
        apppWidgetId,
        R.id.widget_your_id_to_collectionview,
        intent)

فعال سازی یک widget برای قفل نمایشگر دستگاه (lock screen)

از اندروید 4.2 این امکان فراهم شده تا widget های صفحه ی اصلی دستگاه را در صفحه ی قفل (lock screen) نیز جایگذاری نمایید. برای اینکه widget قابلیت قرار گیری در صفحه ی قفل را داشته باشد، لازم است مقدار خصیصه (attribute) android:widgetCategory را در فایل AppWidgetProviderInfo برابر android:widgetCategory قرار دهید. کد زیر نمونه ای را به نمایش می گذارد.


...

در مثال جاری، یک widget تعریف می کنید که قابلیت قرار گیری در صفحه ی اصلی و صفحه ی قفل نمایشگر را داشته باشد. اگر اپلیکیشن خود را هم اکنون recompile و راه اندازی نمایید، خواهید توانست widget را در همین برهه از زمان در صفحه ی قفل نمایشگر قرار دهید.

همچنین می توانید widget category را در زمان اجرای برنامه تشخیص دهید (اینکه آیا زمانی که widget در صفحه ی قفل قرار می گیرد با زمانی که در صفحه ی اصلی نمایش داده می شود دارای ظاهر متفاوتی باشد). برای این منظور، در متد AppWidgetProvider.onUpdate() شما می توانید با استفاده از کد زیر option category یک widget را بررسی نمایید.

Bundle options = appWidgetManager.getAppWidgetOptions(widgetId);
int category = options.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
boolean isLockScreen = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;

با این روش شما می توانید در زمان اجرا تصمیم بگیرید (مشخص کنید) آیا widget ای که اپلیکیشن شما در UI ارائه می دهد بایستی به هنگام نمایش در صفحه ی قفل ظاهری متفاوت داشته باشد یا خیر.

درست مانند زمانی که شما از خصیصه (attribute) android:initialLayout جهت تعریف layout اولیه و چیدمان widget های صفحه ی اصلی استفاده می کنید، android:initialKeyguardLayout را نیز برای تعریف ظاهر widget در صفحه ی قفل نمایشگر، داخل فایل AppWidgetProviderInfo بکار می برید. این layout بلافاصله پس از اینکه widget اضافه می شود، پدیدار شده و زمانی که widget به معنای واقعی مقدار دهی اولیه/راه اندازی می شود با layout و ظاهر اصلی جایگزین می گردد.

تمرین: بروز رسانی widget از طریق یک سرویس

تمرین جاری نحوه ی استفاده از یک سرویس جهت بروز رسانی widget با داده های جدید را به نمایش می گذارد.

کلاس زیر را در پروژه ی خود ایجاد نمایید.

package de.vogella.android.widget.example;
import java.util.Random;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.RemoteViews;
public class UpdateWidgetService extends Service {
        private static final String LOG = "de.vogella.android.widget.example";
        @Override
        public void onStart(Intent intent, int startId) {
                AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
                                .getApplicationContext());
                int[] allWidgetIds = intent
                                .getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
//                ComponentName thisWidget = new ComponentName(getApplicationContext(),
//                                MyWidgetProvider.class);
//                int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
                for (int widgetId : allWidgetIds) {
                        // create some random data
                        int number = (new Random().nextInt(100));
                        RemoteViews remoteViews = new RemoteViews(this
                                        .getApplicationContext().getPackageName(),
                                        R.layout.widget_layout);
                        Log.w("WidgetExample", String.valueOf(number));
                        // Set the text
                        remoteViews.setTextViewText(R.id.update,
                                        "Random: " + String.valueOf(number));
                        // Register an onClickListener
                        Intent clickIntent = new Intent(this.getApplicationContext(),
                                        MyWidgetProvider.class);
                        clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
                        clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
                                        allWidgetIds);
                        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                                        getApplicationContext(), 0, clickIntent,
                                        PendingIntent.FLAG_UPDATE_CURRENT);
                        remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
                        appWidgetManager.updateAppWidget(widgetId, remoteViews);
                }
                stopSelf();
                super.onStart(intent, startId);
        }
        @Override
        public IBinder onBind(Intent intent) {
                return null;
        }
}

این کلاس را به عنوان یک سرویس (با تگ service) در فایل تنظیمات AndroidManifest.xml خود تعریف نمایید.

MyWidgetProvider را به صورت زیر ویرایش نمایید. در حال حاضر کد زیر سرویس را ساخته و آن را راه اندازی می کند.

package de.vogella.android.widget.example;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class MyWidgetProvider extends AppWidgetProvider {
        private static final String LOG = "de.vogella.android.widget.example";
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                        int[] appWidgetIds) {
                Log.w(LOG, "onUpdate method called");
                // Get all ids
                ComponentName thisWidget = new ComponentName(context,
                                MyWidgetProvider.class);
                int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
                // Build the intent to call the service
                Intent intent = new Intent(context.getApplicationContext(),
                                UpdateWidgetService.class);
                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
                // Update the widgets via the service
                context.startService(intent);
        }
}

پس از فراخوانی، این سرویس تمامی widget ها را بروز رسانی می کند. در واقع می توانید با کلیک بر روی یکی از widget های جاری، تمامی widget ها را یکجا بروز آوری نمایید.

1396/01/07 9738 0
نظرات شما

نظرات خود را ثبت کنید...