Как сделать виджет на андроид. Как добавить виджет на экран на Android

vertical” android_updateperiodmillis=”1800000″ xmlns_android=”http://schemas.android.com/apk/res/android”> </appwidget-provider>

Пройдёмся по главным составляющим этого файла.
configure описывает activity отвественную за конфигурацию виджета при добавлении и вообще.
minHeight и minWidth описывает малые размеры для корректного отображения виджета. К огорчению, здесь нет механизма в стиле “1 клетка на 2 клеточки”. На страничке документации по andoroid есть хорошее описание какие размеры должны быть (См. ссылки в конце статьи). В этом примере 1 клеточка в высоту, 2 в ширину.
updatePeriodMillis может быть установлен в  1800000 (30мин). Меньше вроде как не умеет (Вообще умеет, но просит реализации таймера).
resizeMode описывает как юзер может изменять размеры виджета. Можно установить в “none”, тогда размеры изменять будет нельзя. Можно в “horizontal”, можно  в “vertical”, можно в оба сразу “horizontal vertical”. Наименования молвят сами за себя.

Шаг 3. Заходим в AndroidManifest.xml
Добавляем наш виджет и его кофигуратор в секцию <application>:

<!– added –> <receiver android_name=”widgets.MyWidget”>     <intent-filter>         <action android_name=”android.appwidget.action.APPWIDGET_UPDATE” />     </intent-filter>     <meta-data android_name=”android.appwidget.provider”         android:resource=”@xml/example_info” /> </receiver> <activity android_name=”widgets.MyWidgetConfig”>     <intent-filter>         <action android_name=”android.appwidget.action.APPWIDGET_CONFIGURE” />     </intent-filter> </activity> <!– added –>

Шаг 4. Добавляем UI. Добавляем в layout/ два новейших файла через New->XML->Layout XML widget_main.xml widget_main_config.xml В widget_main_config.xml закидываем элементы EditText, Button со последующими ID: configWidgetText configWidgetBtn.

<?xml version=”1.0″ encoding=”utf-8″?> <LinearLayout xmlns_android=”http://schemas.android. Добавим в widget_main последующие элементы: TextView, Button со последующими ID:

widgetText
widgetBtn

Установим ширину и высоту для layout в значения “wrap_content”.

Итого:

<?xml version=”1.0″ encoding=”utf-8″?> <LinearLayout xmlns_android=”http://schemas.android.com/apk/res/android”     android:layout_width=”wrap_content”     android:layout_height=”wrap_content”     android:orientation=”vertical”>     <TextView         android:id=”@+id/widgetText”         android:layout_width=”match_parent”         android:layout_height=”wrap_content”         android:text=”TextView” />     <Button         android:id=”@+id/widgetBtn”         android:layout_width=”match_parent”         android:layout_height=”wrap_content”         android:text=”Button” /> </LinearLayout>

Шаг 5. Вернёмся к MyWidget.java
Виджеты являются в определённом роде BroadcastReciever которые обрабатывают определённые действия. Как и BroadcastReciever, обрабатывают деяния они способом onRevieve() который в предстоящем обрабатывает данные иными способами. Тем не наименее, виджет является наследником класса AppWidgetProvider (в свою очередь, наследник того самого BroadcastReciever), который всё несколько упрощает.
Разглядим что нам дает AppWidgetProvider:
onEnabled — вызывается один раз, когда виджет создаётся (добавляется на экран).
onUpdate — вызывается при обновлении виджета в данный в XML файле интервал. Основной функционал виджета находится конкретно тут. Как уже было сказано, ежели для вас необходимо вызывать этот способ почаще чем раз в 30 минут, следует добавить таймер (используя класс AlarmManager).
onDeleted — вызывается, когда виджет удалён с экрана.
onDisabled — вызывается, когда все виджеты удалены с экрана. Т.е. можно добавлять сколько угодно экземпляров этого виджета, и когда крайний из добавленных будет удалён, этот способ сработает. В этом и отличие от onDeleted
onRestored — вызывается при восстановлении AppWidget из бекапа. Откликается на ACTION_WIDGET_RESTORED. В обыкновенном случае будет сходу вызван onUpdate. Даже не знаю как этот способ можно использовать.
OnAppWidgetOptionsChanged — вызывается при изменении размеров виджета (да, ежели такие конфигурации вообщем разрешены в XML настройках).
onReceive — вызывается для обработки событий иными методами.

Читайте также  Мфу печатает но не сканирует. Почему принтер отказывается сканировать

Наследуем наш класс от AppWidgetProvider (extends AppWidgetProvider).
Жмём правой клавишей на классе, позже Generate -> Override Methods…
Избираем onUpdate и onDelete. 1-ый будет вызываться при обновлении виджета, 2-ой — при удалении. 

Для меня стало открытием, так что на данный момент покажу 🙂
Для контраста, добавим всплывающее окно при удалении виджета через Toast:

@Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); Toast.makeText(context, “Widget deleted”, Toast.LENGTH_SHORT).show(); }

Сейчас переместимся в способ onUpdate.

Важно!
Этот способ будет вызываться в зависимости от опций из  res/xml/example_info.xml но при разработке через конфигуратор он вызван не будет. Будет вызван onEnabled() (но и то как-то, по моим ощущениям, кривовато).

Для начала, установим что-нибудь в 1-ое поле TextView. Какой смысл добавлять что-то в TextView, ежели это изменит текст через данный интервал, тем наиболее, что мы этот текст выставляем в конфигураторе? Смысла в этом нет. Просто это даст чуток наиболее полную картину того, как работать с виджетами. В чём есть смысл, так это в определении кнопочке деяния, т.к. опосля перезагрузки устройства работать она не станет (мы говорим о том, что ежели действие для клавиши будет определяться в конфигруаторе, то эта привязка закончит работать опосля перезагурзки, т.к. в этом случае созданием виджета будет заниматься не конфигуратор а система). Но определять их нужно в onEnabled, т.к. опосля перезагруки конкретно он и будет вызван.
Сделаем экземпляр класса RemoteViews (референс: RemoteViews(String packageName, int layoutId) ). Где обращаемся к context из пренимаемых onUpdate характеристик (берем оттуда имя) и layout самого виджета. Установим текст “Hello widget!” способом .setTextViewText  (референс: setTextViewText(int viewId, CharSequence text)). Опосля что добавим ещё одну строчку, которая укажет приложению на необходимость применить изготовленные конфигурации. Таковой финт не типичен для работы с Activity, но для виджетов каждое изменение в виджете обязано сопровождаться обновлением.
Без такового обновления будет вылетать ошибка “Problem Loading Widget”. Проделывать эти деяния нужно со всеми appWidgetIds. Используем конструкцию for (foreach):

for (int appWidgetId : appWidgetIds) { RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.widget_main); view.setTextViewText(R.id.widgetText, “Hello widget!”); appWidgetManager.updateAppWidget(appWidgetId, view); }

Добавим способ onEnabled и назначим кнопочке на виджете действе: вызов конфигуратора по нажатию. В обыкновенной Activity довольно было бы сделать Intent, но в виджетах употребляется несколько наиболее непростая схема. Итак, необходимо:

  1. Создать Intent. В качетсве характеристик — контекст и имя класса Activity-сонфигуратора с .class в конце. 
  2. Добавить в него ID виджета, который запрашивает вызов конфигуратора (с помошью .putExtra). Ожидается переменная int для «поля» AppWidgetManager.EXTRA_APPWIDGET_ID 
  3. Создать объект PendingIntent, который будет назначен кнопочке для посылки-по-нажатию. См.аргументы ниже. 
Читайте также  Флешка не определяется ошибка 43. Код 43: компьютер не видит USB-флешку

Попутно определим все нужные характеристики ещё раз (тут не плохо было бы помыслить о том, как не повторяться с тем, что мы описывали  в onUpdate). В отличии от onUpdate, принимаемое значение способа лишь context, так что нужно вынуть откуда-то и ID. Для этого вводим объект класса ComponentName. Итак код:
@Override public void onEnabled(Context context) { RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_main); AppWidgetManager awm = AppWidgetManager.getInstance(context); ComponentName compName = new ComponentName(context, MyWidget.class); int[] widgetIds = awm.getAppWidgetIds(compName); for (int widgetId : widgetIds) { Intent intentBtnPwr = new Intent(context, MyWidgetConfig.class); intentBtnPwr.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); PendingIntent pi = PendingIntent.getActivity(context, widgetId, intentBtnPwr, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setOnClickPendingIntent(R.id.widgetBtn, pi); awm.updateAppWidget(widgetId, remoteViews); } }
Шаг 6. Перейдём к MyWidgetConfig.java Объявляем переменные для всего класса. EdText — поле ввода на экране конфигурации виджета awManager — менеджер, который пригодиться для работы с виджетом, thisContext — контекст awID — переменная для хранения ID добавляемого виджета Клавишу добавлять не будем, просто привяжем её к Listener и опишем нужное поведение позднее.

public class NoWolWidgetConfig extends Activity { EditText EdText; AppWidgetManager awManager; Context thisContext; int awID; …

Наследуем класс от Activity, добавляем способ onCreate через Generate… (тем же методом, что описан выше). Ну и сходу привязываем класс к layout.

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.widget_main_config); …

Сейчас установим связку для EditText

EdText = (EditText)findViewById(R.id.configWidgetText);

Опишем Intent, чтоб получить информацию для текущей Activity о том, какой виджет вызвал эту Activity. В 1-ый раз, при добавлении виджета, он помещается на экран и получает собственный ID, опосля что запускается конфигуратор. Ежели итог выполнения конфигуратора не успешен, либо он был закрыт (кнопкой назад, например) виджет удаляется, т. к. не получает результрующего статуса RESULT_OK от конфигуратора. Также во входящем Intent конфигуратор получает ID экземпляра виджета и должен по завершению передать его обратно, также используя механизм Intent. Объявим Intent и привяжем его к полученному:

Intent intent = getIntent();

Сделаем хранилище (Bundle) и выгрузим в него данные из приобретенного интента —присвоем awID значение ID виджета. В случае неудачи просто закроем конфигуратор и тогда виджет сотворен не будет.

Bundle bundleExtras = intent.getExtras(); if (bundleExtras != null){ awID = bundleExtras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); }else finish();

Сейчас определим контекст в переменную и с его внедрением привяжем AppWidgetManager к нашему классу (нужен для таковой же работы с виджетом, как и снутри самого кода виджета). И да, мы уже делали такое чуток ранее:

thisContext = NoWolWidgetConfig.this; awManager = AppWidgetManager.getInstance(thisContext);

Сделаем переменную для RemoteViews которая дозволит обращаться к элементам виджета.

final RemoteViews awRV = new RemoteViews(thisContext.getPackageName(), R.layout.widget_main);

Сейчас привяжем нашу единственную клавишу к listener и опишем её поведение.

findViewById(R.id.configWidgetBtn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Action starts here 😉 } });

Как вы увидели, для неё нет отдельной переменной. Но работать будет 🙂
Сейчас заставим по клику в конфигураторе брать значение из EditText и засовывать его во 2-ой TextView нашего виджета:

awRV.setTextViewText(R.id.widgetText, ((EditText) findViewById(R.id.configWidgetText)).getText().toString());

Назначим кнопочке действие тем же методом, что и ранее мы проделывали в виджете в способе onEnabled.

Intent intentBtnPwr = new Intent(thisContext, MyWidgetConfig.class); intentBtnPwr.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, awID); PendingIntent pi = PendingIntent.getActivity(thisContext, awID, intentBtnPwr, PendingIntent.FLAG_UPDATE_CURRENT); awRV.setOnClickPendingIntent(R.id.widgetBtn, pi);

Опосля всего этого нужно обновить виджет используя способ .updateAppWidget объекта класса AppWidgetManager. Он обновит в виджете лишь то, что мы изменили в виджете и не тронет другое. Проще говоря, смотрите на это как на клавишу «Применить».

awManager.updateAppWidget(awID, awRV);

Сейчас мы передаём итог (ID виджета) в Intent в наш виджет и закрываем Activity конфигуратора. Так виджет будет знать, что конфигуратор удачно выполнился и будет отображен на экране. Поточнее огласить, он не будет с него удалён, что вышло бы при закрытии конфигуратора (повторяюсь).

Intent resultIntent = new Intent(); resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, awID); setResult(RESULT_OK, resultIntent); finish();

Вот что у нас получилось:

Вышло вертикальное видео. На этом пожалуй всё. Как и обещал, код главных компонентов полностью:
manifests/AndroidManifest.xml
<?xml version=”1.0″ encoding=”utf-8″?> <manifest xmlns_android=”http://schemas.android.com/apk/res/android” package=”com.blogspot.developersu.we.widgetexample”> <application     android:allowBackup=”true”     android:icon=”@mipmap/ic_launcher”     android:label=”@string/app_name”     android:roundIcon=”@mipmap/ic_launcher_round”     android:supportsRtl=”true”     android:theme=”@style/AppTheme”>     <activity android_name=”.MainActivity”>         <intent-filter>             <action android_name=”android.intent.action.MAIN” />             <category android_name=”android.intent.category.LAUNCHER” />         </intent-filter>     </activity>     <!– added –>     <receiver android_name=”widgets.MyWidget”>         <intent-filter>             <action android_name=”android.appwidget.action.APPWIDGET_UPDATE” />         </intent-filter>         <meta-data android_name=”android.appwidget.provider”             android:resource=”@xml/example_info” />     </receiver>     <activity android_name=”widgets.MyWidgetConfig”>         <intent-filter>             <action android_name=”android.appwidget.action.APPWIDGET_CONFIGURE” />         </intent-filter>     </activity>     <!– added –> </application> </manifest> com.blogspot.developersu.we.widgetexample/MainActivity
package com.blogspot.developersu.we.widgetexample; /* * It doesn’t make sense to cover this code by any license, ’cause everything described here * has been widely used by thousands of coders all around the world. So most likely I’ve already * stolen this code in their eyes and you’re going to steal it from me. LOL. * Bye! * * Dmitry Isaenko, * 2017, Russia * https://developersu.blogspot.com/2017/07/androidwidget.html * */ import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { int awID; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } widgets/MyWidget
package widgets; 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.widget.RemoteViews; import android.widget.Toast; import com.blogspot.developersu.we.widgetexample.R; public class MyWidget extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); for (int appWidgetId : appWidgetIds) { RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.widget_main); view.setTextViewText(R.id.widgetText, “Hello widget!”); appWidgetManager.updateAppWidget(appWidgetId, view); } } @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); Toast.makeText(context, “Widget deleted”, Toast.LENGTH_SHORT).

Читайте также  Установка виндовс 7 на комп. Пошаговая установка Windows 7: инструкция для новичков

Оставьте комментарий