Как сделать виджет на андроид. Как добавить виджет на экран на 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 — вызывается для обработки событий иными методами.

Читайте также  Установить офис на мак бесплатно. Microsoft Office for Mac Standard 2019 16.28.0 [Multi/Ru] скачать торрент

Наследуем наш класс от 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, который будет назначен кнопочке для посылки-по-нажатию. См.аргументы ниже. 
Читайте также  Как узнать скорость записи флешки. Проверяем реальную скорость флешки

Попутно определим все нужные характеристики ещё раз (тут не плохо было бы помыслить о том, как не повторяться с тем, что мы описывали  в 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).

Читайте также  Сайт не открывается без www. Сайт не открывается С или БЕЗ «www» перед доменным именем

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