Как написать свой виджет для android

Время на прочтение
6 мин

Количество просмотров 41K

На Хабре уже достаточно статей о том, как разработать «hello world»-виджет для устройств на базе Android. Еще больше об этом можно почитать в сети, в том числе и на сайте Google для разработчиков, StackOverflow и других ресурсах. Казалось бы, все подробно разжевано, есть сотни примеров — зачем же писать очередную статью, когда вокруг и так достаточно информации?
Однако, когда мы начали разработку виджета, нам пришлось потратить несколько недель на то, чтобы разобраться с нюансами и реализовать проект так, как мы задумали его изначально.
Надеемся, наш опыт поможет сэкономить время на реализацию вашего виджета.

Подготовка

Для разработки была выбрана Android Stuido.Продукт еще очень сырой, не все разработчики готовы на него перейти, но отличная работа Preview и широкие возможности системы сборки Gradle берут верх над всеми недочетами. Поэтому мы рискнули попробовать, и, как оказалось, не зря.

Для тестирования, помимо непосредственной отладки на тестовом смартфоне, мы также использовали программные эмуляторы. Стандартным пользоваться достаточно проблематично, были рассмотрены различные высокопроизводительные эмуляторы Android-x86, AndroVM, Genymotion, Manymo и другие. В итоге мы выбрали Genymotion — он подкупил своей простотой установки и скоростью работы Android-x86, подробная инструкция по настройке и установке — необходим для тестирования на устройствах с Android 4.0 и ниже.

Данные эмуляторы отлично работают под различными ОС: Linux, Mac, Windows, у разработчиков бывают разные предпочтения, а переубеждать их неправильно, так что кроссплатформенные инструменты выручают.

Также эти программы помогают при автоматизированном тестировании: тесты написаны с использованием Android Instrumentation Framework, JUnit, Robotium. Подробнее об этом в следующей статье, которую мы опубликуем в ближайшее время :)

Проектирование

Итак, мы хотим, чтобы пользователь видел поисковую форму, кнопку голосовых запросов, а при увеличении доступного размера виджета — анонсы актуальных новостей.


По данным Google Play, в мире зарегистрировано около 4500 видов различных устройств с поддержкой Android.


Помимо разрешения экрана, эти устройства могут различаться диагоналями и плотностью точек на единицу площади (ppi). К счастью, задачу можно упростить и для определения размеров элементов виджета использовать аппаратно-независимые пиксели — dp. Большинство смартфонов используют сетку 4×4, для 7-дюймовых планшетов сетка может быть 6×6, да еще и сам размер ячейки зависит от лаунчера и версий API Android. В таблице мы привели получившиеся размеры в dp для различных устройств:

Samsung GT-i9000 Nexus 4 Samsung Tab Nexus 7
1 x 1 64 x 58 64 x 58 74 x 74 80 x 71
2 x 2 144 x 132 152 x 132 148 x 148 176 x 159
4 x 3 304 x 206 328 x 206 296 x 222 368 x 247

Можно отталкиваться от формул:
для API младше 14 размер = (74 x количество ячеек) — 2
для последних версий размер = (70 x количество ячеек) — 30

Если во время тестирования вы сталкиваетесь с проблемами на каком-то конкретном устройстве, например при смене ориентации экрана, то проще добавить отдельный layout или указать нужный размер в dimens.xml, чем пытаться подогнать параметры. Еще на этапе проектирования обратите внимание на повторно используемые элементы, чтобы при разработке вынести их в отдельные layout, а для вставки в необходимое место используйте Include. В нашем приложении данную технологию использовали для новостей, и для реализации тени у некоторых элементов home_news_row.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/news_row"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include
        android:id="@+id/news_item1"
        layout="@layout/home_news_item"/>
    <include
        android:id="@+id/news_item2"
        layout="@layout/home_news_item"/>
</LinearLayout>

home_news_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/news_img"
        android:scaleType="centerCrop"
        android:layout_weight="1"/>
    <TextView
        android:id="@+id/news_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="13sp"/>
</LinearLayout>

Реализация

Данные для виджета мы получаем с сервера в JSON — все достаточно просто и подробно описано в документации. Если у виджета установлен минимальный размер (поисковая строка и иконка голосового запроса), то анонсы актуальных новостей мы не запрашиваем, а при увеличении виджета сначала проверяем, есть ли закэшированные актуальные новости, после чего берем имеющиеся данные, тем самым экономя трафик и батарейку.

Проанализировав текущее распространение версий Android мы выяснили, что версия 2.2 все еще актуальна и ее необходимо поддерживать. К сожалению, поддержка изменения размеров виджета доступна только с версии 3.0, поэтому для более старых версий сделаем статичную версию развернутого виджета. Доля устройств версий 3.x на текущий момент несущественна, и мы решили реагировать на изменение размера виджета начиная с Android 4.1 c помощью метода onAppWidgetOptionsChanged. Но не все с ним гладко: он не срабатывает в некоторых модифицированных прошивках. Пришлось искать альтернативное решение, и оно нашлось: мы использовали событие com.sec.android.widgetapp.APPWIDGET_RESIZE в методе onReceive():

public void onReceive(Context context, Intent intent) {
        if (intent.getAction().contentEquals("com.sec.android.widgetapp.APPWIDGET_RESIZE")) {
            handleResize(context, intent);
        }

        super.onReceive(context, intent);
    }

    private void handleResize(Context context, Intent intent) {
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        Bundle newOptions = getOptions(context, intent);
        int appWidgetId = intent.getIntExtra("widgetId", 0);

        if (!newOptions.isEmpty()) {
            onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
        }
    }

    public Bundle getOptions(Context context, Intent intent) {
        Bundle newOptions = new Bundle();

        int appWidgetId = intent.getIntExtra("widgetId", 0);
        int widgetSpanX = intent.getIntExtra("widgetspanx", 0);
        int widgetSpanY = intent.getIntExtra("widgetspany", 0);

        if(appWidgetId > 0 && widgetSpanX > 0 && widgetSpanY > 0) {
            newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, widgetSpanY * 74);
            newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, widgetSpanX * 74);
        }
        return newOptions;
    }

    @Override
    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
	Log.d("height", newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT));
	Log.d("width", newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH));
}

При установке виджета на домашний экран, пользователь может выбрать в настройках цвет и прозрачность. В данной реализации нет нечего сложного, но есть один нюанс: уровень прозрачности необходимо добавить к выбранному цвету. Например, вот так это реализовано у нас:

int color = Color.parseColor(“#FFFFFF”);
int transparent =150;
color = Color.argb(transparent, Color.red(color), Color.green(color), Color.blue(color));

Полученный цвет с уровнем прозрачности применяется к элементу виджета. В нашем случае мы просто устанавливаем setBackgroundColor() у LinearLayout.

Также бывают ситуации, когда в альбомном режиме размер ячейки виджета получается меньше, чем в портретном, в связи с чем текст заданной длины уже не помещается. Можно попробовать уменьшить размер текста, но на устройствах с низким разрешением он становится нечитаемым. В связи с этим при смене ориентации мы просто уменьшаем в layout альбомного режима количество выводимых строк text.setMaxLines(2), а размер шрифта оставляем прежним:

android:maxLines="3"
android:ellipsize="end"

Последнее свойство добавляет в конце строки многоточие.

Для того, чтобы наш виджет было легче найти в списке установленных, нужен последний штрих: подготовка картинок-превью, или previewImage. Можно попытаться воспроизвести итоговый виджет в графическом редакторе, мы же воспользовались приложением Widget Preview.

Вот что получилось в итоге:

Скачать итоговое приложение можно тут.

Спасибо за внимание!

Widgets are the micro-version of the application that consists of some functionality of the application that is displayed only on the Home Screens or the Lock Screen. For example, we see Weather, Time, Google Search Bars on the Home Screen, and FaceLock, FingerprintLock on the Lock Screen, which are some of the Widgets available on the device. Widgets come along with the Application when you install it or download it from the Web. Generally, phones come with a manufacturing configuration but such elements can be adjusted by a user later in time. In this article, we demonstrate how one can implement a basic widget for an Android App.

Time Widget, Weather Widget, Google Search Bar Widget

Steps for Creating a Basic Widget

Step 1: Create a New Project

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. We are implementing it for both Java and Kotlin languages.

Step 2: Add the App Widget to the Project

Right-Click on the app, move the cursor to new, find the “Widget” option at the end, select it.

widget screenshot

Specify the required properties for the widget such as min. width and height, config file and preferred language, etc, and proceed. Files are automatically generated.

widget screenshot

Step 3: Install and Run the Code

  • Install and Run the code on Android Virtual Device (AVD) or a personal device.
  • Open the widget section of the phone, lookup for a widget with the Application name, select it, bring it to the home screen.
  • Try changing the dimensions and we are done!

Output: Run On Emulator

What extra files are generated in this process?

During this selecting and deploying process, a few extra files are generated and minor changes are made to existing files as well. No programming is required for generating a basic widget and is only required if an application is to be embedded inside the widget, as discussed in the later parts of the article. Let us now explain the newly generated files the changes make to the existing ones, one by one.

1. NewAppWidget.kt

Where it’s generated?

NewAppWidget

Kotlin

import android.appwidget.AppWidgetManager 

import android.appwidget.AppWidgetProvider 

import android.content.Context 

import android.widget.RemoteViews 

class NewAppWidget : AppWidgetProvider() { 

    override fun onUpdate( 

        context: Context, 

        appWidgetManager: AppWidgetManager, 

        appWidgetIds: IntArray 

    ) { 

        for (appWidgetId in appWidgetIds) { 

            updateAppWidget(context, appWidgetManager, appWidgetId) 

        

    

    override fun onEnabled(context: Context) { 

    

    override fun onDisabled(context: Context) { 

    

internal fun updateAppWidget( 

    context: Context, 

    appWidgetManager: AppWidgetManager, 

    appWidgetId: Int 

) { 

    val widgetText = context.getString(R.string.appwidget_text) 

    val views = RemoteViews(context.packageName, R.layout.new_app_widget) 

    views.setTextViewText(R.id.appwidget_text, widgetText) 

    appWidgetManager.updateAppWidget(appWidgetId, views) 

}

Java

import android.appwidget.AppWidgetManager;

import android.appwidget.AppWidgetProvider;

import android.content.Context;

import android.widget.RemoteViews;

class NewAppWidget extends AppWidgetProvider {

    @Override

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)

    {

        for (int appWidgetId : appWidgetIds) {updateAppWidget(context, appWidgetManager, appWidgetId);

        }

    }

    @Override public void onEnabled(Context context)

    {

        super.onEnabled(context);

    }

    @Override public void onDisabled(Context context)

    {

        super.onDisabled(context);

    }

    private void

    updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId)

    {

        String widgetText = context.getString(R.string.appwidget_text);

        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

        views.setTextViewText(R.id.appwidget_text, widgetText);

        appWidgetManager.updateAppWidget(appWidgetId, views);

    }

}

2. new_app_widget.xml

Where it’s generated?

XML

<RelativeLayout

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="#09C"

    android:padding="@dimen/widget_margin"

    <TextView

        android:id="@+id/appwidget_text"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_centerVertical="true"

        android:layout_margin="8dp"

        android:background="#09C"

        android:contentDescription="@string/appwidget_text"

        android:text="@string/appwidget_text"

        android:textColor="#ffffff"

        android:textSize="24sp"

        android:textStyle="bold|italic" /> 

</RelativeLayout>

3. dimens.xml

Where it’s generated?

XML

<?xml version="1.0" encoding="utf-8"?> 

<resources

    <dimen name="widget_margin">8dp</dimen

</resources>

4. new_app_widget_info.xml

Where it’s generated?

XML

<?xml version="1.0" encoding="utf-8"?> 

<appwidget-provider

    android:initialKeyguardLayout="@layout/new_app_widget"

    android:initialLayout="@layout/new_app_widget"

    android:minWidth="40dp"

    android:minHeight="40dp"

    android:previewImage="@drawable/example_appwidget_preview"

    android:resizeMode="horizontal|vertical"

    android:updatePeriodMillis="86400000"

    android:widgetCategory="home_screen"

</appwidget-provider>

5. Changes made to AndroidManifest.xml file

XML

<?xml version="1.0" encoding="utf-8"?> 

    package="org.geeksforgeeks.widget_basic"

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

        <receiver android:name=".NewAppWidget"

            <intent-filter

                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 

            </intent-filter

            <meta-data

                android:name="android.appwidget.provider"

                android:resource="@xml/new_app_widget_info" /> 

        </receiver

        <activity android:name=".MainActivity"

            <intent-filter

                <action android:name="android.intent.action.MAIN" /> 

                <category android:name="android.intent.category.LAUNCHER" /> 

            </intent-filter

        </activity

    </application

</manifest>

Is Programming Still Required? If so, which part of the code is to be changed? (In Continuation)

Yes, Programming is still a requirement for creating widgets. Changes are made inside the NewAppWidget.kt which is a Kotlin class and its counterpart new_app_widget.xml file that displays the widget. Functionalities can be declared inside the update app widget function for the application operations and new_app_widget.xml for adding multiple elements to the widget’s display. Since both the files are linked internally, altering one of them brings changes to another. 

Regarding implementing multiple Widgets 

There are no restrictions on the number of widgets that an app can have, however, it is advised to have a minimum number of widgets as possible as widgets are dynamically changing elements. There are update callbacks (refer to new_app_widget_info.xml file ), updatePeriodMillis is a parameter referring to which the application keeps updating the widget, meaning, the application thread to update the widget keeps running in the background, acquiring some part of the limited RAM.

Widgets are the micro-version of the application that consists of some functionality of the application that is displayed only on the Home Screens or the Lock Screen. For example, we see Weather, Time, Google Search Bars on the Home Screen, and FaceLock, FingerprintLock on the Lock Screen, which are some of the Widgets available on the device. Widgets come along with the Application when you install it or download it from the Web. Generally, phones come with a manufacturing configuration but such elements can be adjusted by a user later in time. In this article, we demonstrate how one can implement a basic widget for an Android App.

Time Widget, Weather Widget, Google Search Bar Widget

Steps for Creating a Basic Widget

Step 1: Create a New Project

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. We are implementing it for both Java and Kotlin languages.

Step 2: Add the App Widget to the Project

Right-Click on the app, move the cursor to new, find the “Widget” option at the end, select it.

widget screenshot

Specify the required properties for the widget such as min. width and height, config file and preferred language, etc, and proceed. Files are automatically generated.

widget screenshot

Step 3: Install and Run the Code

  • Install and Run the code on Android Virtual Device (AVD) or a personal device.
  • Open the widget section of the phone, lookup for a widget with the Application name, select it, bring it to the home screen.
  • Try changing the dimensions and we are done!

Output: Run On Emulator

What extra files are generated in this process?

During this selecting and deploying process, a few extra files are generated and minor changes are made to existing files as well. No programming is required for generating a basic widget and is only required if an application is to be embedded inside the widget, as discussed in the later parts of the article. Let us now explain the newly generated files the changes make to the existing ones, one by one.

1. NewAppWidget.kt

Where it’s generated?

NewAppWidget

Kotlin

import android.appwidget.AppWidgetManager 

import android.appwidget.AppWidgetProvider 

import android.content.Context 

import android.widget.RemoteViews 

class NewAppWidget : AppWidgetProvider() { 

    override fun onUpdate( 

        context: Context, 

        appWidgetManager: AppWidgetManager, 

        appWidgetIds: IntArray 

    ) { 

        for (appWidgetId in appWidgetIds) { 

            updateAppWidget(context, appWidgetManager, appWidgetId) 

        

    

    override fun onEnabled(context: Context) { 

    

    override fun onDisabled(context: Context) { 

    

internal fun updateAppWidget( 

    context: Context, 

    appWidgetManager: AppWidgetManager, 

    appWidgetId: Int 

) { 

    val widgetText = context.getString(R.string.appwidget_text) 

    val views = RemoteViews(context.packageName, R.layout.new_app_widget) 

    views.setTextViewText(R.id.appwidget_text, widgetText) 

    appWidgetManager.updateAppWidget(appWidgetId, views) 

}

Java

import android.appwidget.AppWidgetManager;

import android.appwidget.AppWidgetProvider;

import android.content.Context;

import android.widget.RemoteViews;

class NewAppWidget extends AppWidgetProvider {

    @Override

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)

    {

        for (int appWidgetId : appWidgetIds) {updateAppWidget(context, appWidgetManager, appWidgetId);

        }

    }

    @Override public void onEnabled(Context context)

    {

        super.onEnabled(context);

    }

    @Override public void onDisabled(Context context)

    {

        super.onDisabled(context);

    }

    private void

    updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId)

    {

        String widgetText = context.getString(R.string.appwidget_text);

        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

        views.setTextViewText(R.id.appwidget_text, widgetText);

        appWidgetManager.updateAppWidget(appWidgetId, views);

    }

}

2. new_app_widget.xml

Where it’s generated?

XML

<RelativeLayout

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="#09C"

    android:padding="@dimen/widget_margin"

    <TextView

        android:id="@+id/appwidget_text"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_centerVertical="true"

        android:layout_margin="8dp"

        android:background="#09C"

        android:contentDescription="@string/appwidget_text"

        android:text="@string/appwidget_text"

        android:textColor="#ffffff"

        android:textSize="24sp"

        android:textStyle="bold|italic" /> 

</RelativeLayout>

3. dimens.xml

Where it’s generated?

XML

<?xml version="1.0" encoding="utf-8"?> 

<resources

    <dimen name="widget_margin">8dp</dimen

</resources>

4. new_app_widget_info.xml

Where it’s generated?

XML

<?xml version="1.0" encoding="utf-8"?> 

<appwidget-provider

    android:initialKeyguardLayout="@layout/new_app_widget"

    android:initialLayout="@layout/new_app_widget"

    android:minWidth="40dp"

    android:minHeight="40dp"

    android:previewImage="@drawable/example_appwidget_preview"

    android:resizeMode="horizontal|vertical"

    android:updatePeriodMillis="86400000"

    android:widgetCategory="home_screen"

</appwidget-provider>

5. Changes made to AndroidManifest.xml file

XML

<?xml version="1.0" encoding="utf-8"?> 

    package="org.geeksforgeeks.widget_basic"

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

        <receiver android:name=".NewAppWidget"

            <intent-filter

                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 

            </intent-filter

            <meta-data

                android:name="android.appwidget.provider"

                android:resource="@xml/new_app_widget_info" /> 

        </receiver

        <activity android:name=".MainActivity"

            <intent-filter

                <action android:name="android.intent.action.MAIN" /> 

                <category android:name="android.intent.category.LAUNCHER" /> 

            </intent-filter

        </activity

    </application

</manifest>

Is Programming Still Required? If so, which part of the code is to be changed? (In Continuation)

Yes, Programming is still a requirement for creating widgets. Changes are made inside the NewAppWidget.kt which is a Kotlin class and its counterpart new_app_widget.xml file that displays the widget. Functionalities can be declared inside the update app widget function for the application operations and new_app_widget.xml for adding multiple elements to the widget’s display. Since both the files are linked internally, altering one of them brings changes to another. 

Regarding implementing multiple Widgets 

There are no restrictions on the number of widgets that an app can have, however, it is advised to have a minimum number of widgets as possible as widgets are dynamically changing elements. There are update callbacks (refer to new_app_widget_info.xml file ), updatePeriodMillis is a parameter referring to which the application keeps updating the widget, meaning, the application thread to update the widget keeps running in the background, acquiring some part of the limited RAM.

Начиная с Android 1.5, виджеты приложений позволяют пользователям получать информацию, управлять приложениями и выполнять важные задачи, не выходя из своих домашних экранов.

В этой серии из двух частей я покажу вам, как обеспечить лучший пользовательский опыт, добавив виджет приложения в свои проекты Android.

К концу серии вы создадите виджет, который:

  • Отображает несколько наборов данных.
  • Выполняет уникальное действие, когда пользователь взаимодействует с определенным View в макете этого виджета.
  • Обновляется автоматически по истечении заданного периода времени.
  • Обновления с новыми данными в ответ на взаимодействие с пользователем.

В этом первом посте мы будем использовать встроенные инструменты Android Studio, чтобы быстро и легко создавать все файлы, необходимые для доставки любого виджета приложения Android. Затем мы расширим этот фундамент для создания виджета, который извлекает и отображает данные и отвечает на события onClick .

Что такое виджеты приложений?

Виджет приложения — это легкое миниатюрное приложение, которое обычно относится к одной из следующих категорий:

  • Информационный виджет. Не прокручиваемый виджет, который отображает важную информацию, такую ​​как виджет погоды или часов.
  • Коллекция виджетов. Прокручиваемый виджет, который отображает ряд связанных элементов, таких как галерея фотографий или статей из той же публикации. Коллекционные виджеты обычно поддерживаются источником данных, таким как Array или база данных. Виджет коллекции должен включать в себя ListView , GridView , StackView или AdapterViewFlipper .
  • Управляйте виджетами. Виджет, который выступает в качестве пульта дистанционного управления для вашего приложения, позволяя пользователю запускать часто используемые функции без необходимости запуска вашего приложения. Приложения, которые воспроизводят музыку, часто предоставляют виджет, который позволяет пользователю воспроизводить, приостанавливать и пропускать дорожки прямо со своего домашнего экрана.
  • Гибридные виджеты. Зачем ограничивать себя одной категорией, если вы можете выбирать элементы из нескольких категорий? Просто имейте в виду, что смешивание и сопоставление могут привести к путанице в работе пользователя, поэтому для достижения наилучших результатов вы должны разработать свой виджет с учетом одной категории, а затем добавлять элементы из других категорий по мере необходимости. Например, если вы хотите создать виджет, который отображает прогноз погоды на сегодня, но также позволяет пользователям просматривать прогноз для разных дней и местоположений, вам следует создать информационный виджет, а затем добавить необходимые элементы управления.

В дополнение к вышеперечисленным функциям большинство виджетов реагируют на события onClick , запуская ассоциированное с ними приложение, аналогично ярлыку приложения, но они также могут предоставлять прямой доступ к определенному контенту в этом приложении.

Виджеты приложений должны быть размещены внутри хоста виджетов приложений , чаще всего на стандартном домашнем экране Android, хотя есть некоторые сторонние хосты виджетов приложений, такие как популярные Nova Launcher и Apex Launcher .

На протяжении всей этой серии я буду говорить о виджетах как о чем-то, что вы помещаете на домашний экран, но если у вас есть смутные воспоминания о возможности разместить виджеты на экране блокировки, то это был не просто какой-то чудесный сон! Между уровнями API 17 и 20 можно было размещать виджеты на домашнем экране или на экране блокировки.

Так как виджеты блокировки экрана устарели на уровне API 21, в этой серии мы создадим виджет только для домашнего экрана.

Почему я должен создать виджет приложения?

Есть несколько причин, почему вы должны рассмотреть возможность добавления виджета приложения в ваш последний проект Android.

Легкий доступ к важной информации и функциям

Виджеты позволяют пользователю просматривать самую важную информацию вашего приложения прямо на рабочем столе. Например, если вы разработали приложение для календаря, вы можете создать виджет, который отображает сведения о следующей встрече пользователя. Это гораздо удобнее, чем заставлять пользователя запускать ваше приложение и потенциально перемещаться по нескольким экранам, просто чтобы получить одну и ту же информацию.

Если вы разрабатываете виджет управления (или гибридный виджет с элементами управления), пользователь также может выполнять задачи прямо со своего домашнего экрана. Продолжая наш пример с календарем, ваш виджет может позволить пользователю создавать, редактировать и отменять встречи, даже не запуская ваше приложение. Это может удалить несколько шагов навигации из некоторых наиболее важных задач вашего приложения, что может оказать только положительное влияние на взаимодействие с пользователем!

Прямой доступ ко всем наиболее важным экранам вашего приложения

При нажатии на виджет пользователь обычно переходит на верхний уровень связанного приложения, аналогично ярлыку приложения. Однако, в отличие от ярлыков приложений, виджеты могут ссылаться на определенные области в связанном приложении. Например, если нажать на уведомление о получении нового электронного сообщения от виджета, можно запустить приложение с уже выбранным новым сообщением, а при нажатии « Создать новое электронное письмо» они могут быть ComposeEmail непосредственно в активность приложения ComposeEmail .

Внедряя несколько ссылок в макет вашего виджета, вы можете обеспечить удобный доступ одним нажатием ко всем наиболее важным действиям вашего приложения.

Создать базу лояльных, активных пользователей

Как доказал весь взрыв Pokemon Go и последующее прекращение его работы, получение тонны людей для загрузки вашего приложения не гарантирует автоматически базу лояльных пользователей, которые все еще будут использовать ваше приложение дни, недели или даже месяцы .

Мобильные пользователи — довольно изменчивая группа, и с ростом памяти, доступной на вашем обычном Android-смартфоне или планшете, легко потерять отслеживание приложений, установленных на вашем устройстве. Скорее всего, если вы возьмете свой Android-смартфон или планшет прямо сейчас и проведете через панель приложений, то вы обнаружите хотя бы одно приложение, о котором вы полностью забыли.

Создавая виджет, который демонстрирует всю наиболее ценную информацию и функции вашего приложения, вы гарантируете, что каждый раз, когда пользователь смотрит на свой домашний экран, ему напоминают не только о том, что ваше приложение существует, но и о том, что оно имеет какой-то отличный контент.

Добавление виджета приложения в ваш проект

Даже самый простой виджет требует нескольких классов и ресурсов, но когда вы создаете виджет с помощью встроенных инструментов Android Studio, все эти файлы создаются для вас. Поскольку нет смысла делать разработку для Android более сложной, чем нужно, мы будем использовать эти инструменты, чтобы получить преимущество при создании нашего виджета.

Виджет приложения всегда должен быть привязан к базовому приложению, поэтому создайте новый проект Android с настройками по вашему выбору.

Как только Android Studio создаст ваш проект, выберите « Файл»> «Создать»> «Виджет»> «AppWidget» на панели инструментов «Android Studio». Это запускает меню Configure Component, где вы можете определить некоторые из начальных настроек вашего виджета.

Настройте параметры виджетов в Android Studio

Большинство из этих вариантов довольно очевидны, но есть некоторые, которые стоит изучить более подробно.

Изменение размера (API 12+)

Если размер виджета можно изменить, пользователь может увеличивать или уменьшать количество «ячеек», которые он занимает на рабочем столе, долгим нажатием на виджет и затем перетаскивая синие маркеры, которые появляются вокруг его контура.

Везде, где возможно, вы должны дать своему виджету возможность изменять размеры по горизонтали и вертикали, поскольку это поможет вашему виджету адаптироваться к ряду конфигураций экрана и настроек домашнего экрана. Если у пользователя серьезно перегружен домашний экран, то ваш виджет может даже не поместиться на этом домашнем экране, если размер вашего виджета не изменяется.

Если вы хотите создать виджет без изменения размера, откройте раскрывающееся меню «Изменить размер» и выберите « Только по горизонтали» , « Только по вертикали» или « Не изменять размер» .

Минимальная ширина и высота

Минимальная ширина и высота определяет количество ячеек, которые ваш виджет будет первоначально занимать при размещении на рабочем столе.

Для виджетов с изменяемым размером это наименьший размер, по которому пользователь может изменить размер вашего виджета, поэтому вы можете использовать эти значения, чтобы пользователи не могли сжимать ваш виджет до такой степени, что он станет непригодным для использования.

Если размер вашего виджета не изменяется, то минимальные значения ширины и высоты — это постоянные ширина и высота вашего виджета.

Чтобы увеличить шансы удобного размещения виджета на ряде домашних экранов, никогда не рекомендуется использовать что-либо большее, чем 4 на 4, для минимальных значений ширины и высоты.

Хотя точная ширина и высота «ячейки» домашнего экрана варьируются в зависимости от устройства, вы можете получить приблизительную оценку того, сколько точек на дюйм (точек на дюйм) будет занимать ваш виджет, используя следующую формулу:

Например, если ваш виджет имеет 2 х 3 ячейки:

1

2

70 x 2 — 30 = 110

70 x 3 — 30 = 180

Этот виджет будет занимать около 110 x 180 точек на дюйм на домашнем экране пользователя. Если эти значения не совпадают с размерами ячеек определенного устройства, Android автоматически округлит ваш виджет до ближайшего размера ячейки.

Просмотрите все параметры в этом меню и внесите необходимые изменения (я придерживаюсь настроек по умолчанию), а затем нажмите « Готово» .

Android Studio теперь сгенерирует все файлы и ресурсы, необходимые для доставки основного виджета приложения. Этот виджет не совсем интересен (в основном это синий блок с надписью « Пример» ), но это функциональный виджет, который вы можете протестировать на своем устройстве.

Чтобы проверить виджет:

  • Установите свой проект на физическое устройство Android или AVD (Android Virtual Device).
  • Запустите средство выбора виджетов для Android нажав любое пустое место на рабочем столе, а затем коснувшись виджета со словом, который появляется в нижней части экрана.
  • Проведите пальцем по палитре виджетов, пока не увидите синий виджет « Пример» .
  • Нажмите на этот виджет, чтобы разместить его на рабочем столе.
  • Войдите в режим изменения размера , нажимая на виджет до тех пор, пока не появится набор синих маркеров, а затем перетащите эти маркеры, чтобы увеличить или уменьшить количество ячеек, занимаемых этим виджетом.

Проверьте свой виджет на виртуальном Android

Изучение файлов виджетов приложения

Этот виджет может делать не так много, но он включает в себя все классы и ресурсы, над которыми мы будем работать в оставшейся части этой серии, поэтому давайте посмотрим на эти файлы и их роль в доставке виджета приложения.

NewAppWidget.java

Поставщик виджетов — это удобный класс, содержащий методы, используемые для программного взаимодействия с виджетом через широковещательные события. Под капотом виджет, по сути, является просто BroadcastReceiver который может реагировать на различные действия, например, пользователь размещает новый экземпляр виджета на своем домашнем экране.

В частности, поставщик виджетов приложения — это место, где вы определяете методы жизненного цикла вашего виджета, которые либо вызываются для каждого экземпляра виджета, либо только для конкретных экземпляров.

Хотя мы склонны думать о виджете как об едином объекте, который пользователь размещает на своем домашнем экране один раз, ничто не мешает ему создавать несколько экземпляров одного и того же виджета. Возможно, ваш виджет настраивается до такой степени, что разные экземпляры могут иметь существенно различную функциональность, или, может быть, пользователь просто настолько любит ваш виджет, что ему хочется намазать его на весь рабочий стол!

Давайте посмотрим на различные методы жизненного цикла, которые вы можете реализовать в классе провайдера виджетов:

Событие onReceive

Android вызывает метод onReceive() зарегистрированного BroadcastReceiver всякий раз, когда происходит указанное событие.

Обычно вам не нужно реализовывать этот метод вручную, поскольку класс AppWidgetProvider автоматически фильтрует все широковещательные рассылки виджетов и делегирует операции соответствующим методам.

Событие onEnabled

onEnabled() жизненного цикла onEnabled() вызывается в ответ на ACTION_APPWIDGET_ENABLED , который транслируется, когда пользователь добавляет первый экземпляр вашего виджета на свой ACTION_APPWIDGET_ENABLED . Если пользователь создает два экземпляра вашего виджета, то onEnabled() вызывается для первого экземпляра, но не для второго.

В этом методе жизненного цикла вы выполняете любую настройку, которая должна выполняться только один раз для всех экземпляров виджета, например, создание базы данных или настройка службы.

Обратите внимание, что если пользователь удаляет все экземпляры вашего виджета со своего устройства, а затем создает новый экземпляр, он классифицируется как первый, и, следовательно, метод onEnabled() будет вызван еще раз.

Событие onAppWidgetOptionsChanged

Этот метод жизненного цикла вызывается в ответ на ACTION_APPWIDGET_OPTIONS_CHANGED , который транслируется, когда создается экземпляр виджета и каждый раз, когда виджет изменяется. Вы можете использовать этот метод для отображения или скрытия контента в зависимости от того, как пользователь изменяет размеры вашего виджета, хотя этот обратный вызов поддерживается только в Android 4.1 и выше.

Событие onUpdate

onUpdate() жизненного цикла onUpdate() вызывается каждый раз:

  • Интервал обновления истек.
  • Пользователь выполняет действие, которое запускает метод onUpdate() .
  • Пользователь размещает новый экземпляр виджета на своем домашнем экране (если только ваш виджет не содержит конфигурационное действие, которое мы рассмотрим во второй части).

onUpdate() жизненного цикла onUpdate() также вызывается в ответ на ACTION_APPWIDGET_RESTORED , который транслируется всякий раз, когда виджет восстанавливается из резервной копии.

Для большинства проектов метод onUpdate() будет содержать основную часть кода провайдера виджета, тем более что здесь также регистрируются обработчики событий вашего виджета.

Событие onDeleted

Метод onDeleted() вызывается каждый раз, когда экземпляр вашего виджета удаляется с хоста виджета приложения, который запускает трансляцию ACTION_APPWIDGET_DELETED системы.

Событие onDisabled

Этот метод вызывается в ответ на трансляцию ACTION_APPWIDGET_DISABLED , которая отправляется, когда последний экземпляр вашего виджета удаляется с хоста виджета приложения. Например, если пользователь создал три экземпляра вашего виджета, метод onDisabled() будет вызываться только тогда, когда пользователь удаляет третий и последний экземпляр со своего onDisabled() .

В onDisabled() жизненного цикла onDisabled() вы должны очистить все ресурсы, созданные в onEnabled() , поэтому, если вы настроите базу данных в onEnabled() вы удалите ее в onDisabled() .

Событие onRestored

Метод onRestored() вызывается в ответ на ACTION_APPWIDGET_RESTORED , который транслируется всякий раз, когда экземпляр виджета приложения восстанавливается из резервной копии. Если вы хотите сохранить какие-либо постоянные данные, то вам нужно переопределить этот метод и переназначить предыдущие AppWidgetIds на новые значения, например:

1

2

3

4

public void onRestored(Context context, int[] oldWidgetIds,

           int[] newWidgetIds) {

   }

}

Если вы откроете файл NewAppWidget.java, который автоматически сгенерировал Android Studio, вы увидите, что он уже содержит реализации некоторых из этих методов жизненного цикла виджета:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

import android.appwidget.AppWidgetManager;

import android.appwidget.AppWidgetProvider;

import android.content.Context;

import android.widget.RemoteViews;

//All widgets extend the AppWidgetProvider class//

public class NewAppWidget extends AppWidgetProvider {

static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,

                              int appWidgetId) {

      CharSequence widgetText = context.getString(R.string.appwidget_text);

    //Load the layout resource file into a RemoteViews object//

      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

      views.setTextViewText(R.id.appwidget_text, widgetText);

 //Tell the AppWidgetManager about the updated RemoteViews object//

      appWidgetManager.updateAppWidget(appWidgetId, views);

  }

//Define the onUpdate lifecycle method//

  @Override

  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

//appWidgetIds is an array of IDs that identifies every instance of your widget, so this

//particular onUpdate() method will update all instances of our application widget//

      for (int appWidgetId : appWidgetIds) {

          updateAppWidget(context, appWidgetManager, appWidgetId);

      }

  }

  @Override

//Define the onEnabled lifecycle method//

  public void onEnabled(Context context) {

      //To do//

  }

  @Override

//Define the onDisabled method//

  public void onDisabled(Context context) {

//To do//

  }

}

Файл макета виджета

Файл res / layout / new_app_widget.xml определяет макет нашего виджета, который в настоящее время представляет собой просто синий фон с надписью « Пример» .

Основное различие между созданием макета для Activity и созданием макета для виджета заключается в том, что макеты виджетов должны основываться на RemoteViews , поскольку это позволяет Android отображать макет в процессе вне вашего приложения (то есть на домашнем экране пользователя).

RemoteViews не поддерживают все виды макетов или View , поэтому при создании макета виджета вы ограничены следующими типами:

  • AnalogClock
  • Button
  • Chromometer
  • FrameLayout
  • GridLayout
  • ImageButton
  • ImageView
  • LinearLayout
  • ProgressBar
  • RelativeLayout
  • TextView
  • ViewStub

Если вы создаете виджет коллекции, вы также можете использовать следующие типы, когда ваше приложение установлено на Android 3.0 и выше:

  • AdapterViewFlipper
  • GridView
  • ListView
  • StackView
  • ViewFlipper

Подклассы и потомки вышеупомянутых Views и классов не поддерживаются.

Щелчки и Размах

Чтобы пользователи случайно не взаимодействовали с виджетом во время навигации по своему домашнему экрану, виджеты реагируют только на события onClick .

Исключение составляют случаи, когда пользователь удаляет виджет, перетаскивая его к действию « Удалить» на домашнем экране, так как в этом случае ваш виджет будет реагировать на жест вертикальной прокрутки. Тем не менее, поскольку этим взаимодействием управляет система Android, вам не нужно беспокоиться о реализации поддержки вертикальной прокрутки в вашем приложении.

Информационный файл виджета

Файл res / xml / new_app_widget_info.xml (также известный как файл AppWidgetProviderInfo) определяет ряд свойств виджета, включая многие параметры, выбранные в меню « Конфигурировать компонент» в Android Studio, например минимальные размеры вашего виджета и возможность их размещения. на экране блокировки.

В файле конфигурации также указывается, как часто ваш виджет запрашивает новую информацию из службы обновлений виджетов приложений. Выбор этой частоты требует от вас сложного баланса: более длительные интервалы обновления помогут сэкономить заряд батареи устройства, но слишком сильно расставляют интервалы, и ваш виджет может отображать заметно устаревшую информацию.

Вы также должны знать, что система разбудит спящее устройство, чтобы получить новую информацию, поэтому хотя обновление вашего виджета каждые полчаса может показаться чрезмерным, это может привести к тому, что ваш виджет разбудит устройство раз в 30 минут, что будет влиять на потребление батареи.

Если вы откроете файл своего проекта new_app_widget_info.xml , то увидите, что он уже определяет ряд свойств виджета, включая интервал обновления.

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

<?xml version=»1.0″ encoding=»utf-8″?>

<appwidget-provider xmlns:android=»http://schemas.android.com/apk/res/android»

//The layout your widget should use when it’s placed on the lockscreen on supported devices//

  android:initialKeyguardLayout=»@layout/new_app_widget»

//The layout your widget should use when it’s placed on the homescreen//

  android:initialLayout=»@layout/new_app_widget»

//The minimum space your widget consumes, which is also its initial size//

  android:minHeight=»40dp»

  android:minWidth=»40dp»

//The drawable that represents your widget in the Widget Picker//

  android:previewImage=»@drawable/example_appwidget_preview»

//Whether the widget can be resized horizontally, vertically, or along both axes, on Android 3.1 and higher//

  android:resizeMode=»horizontal|vertical»

//How frequently your widget should request new information from the app widget provider//

  android:updatePeriodMillis=»86400000″

//Whether the widget can be placed on the homescreen, lockscreen (“keyguard”) or both.//

//On Android 5.0 and higher, home_screen is the only valid option//

  android:widgetCategory=»home_screen»></appwidget-provider>

Если вы дадите своим пользователям возможность разместить свой виджет на экране блокировки, имейте в виду, что содержимое виджета будет видно любому, кто даже взглянет на экран блокировки. Если ваш макет «по умолчанию» содержит какую-либо личную или потенциально конфиденциальную информацию, вы должны предоставить альтернативный макет для вашего виджета, который будет использоваться, когда он размещен на экране блокировки.

Файл res / values ​​/ dimensions.xml

Виджеты выглядят не лучшим образом, когда они прижаты друг к другу или расширяются до самого края рабочего стола.

Всякий раз, когда ваш виджет отображается на Android 4.0 или выше, операционная система Android автоматически вставляет некоторые отступы между рамкой виджета и ограничительной рамкой.

Виджет состоит из ограничивающих рамок, поля виджета, полей виджета и элементов управления виджета.

Если ваше приложение запускается на устройстве, которое работает на более ранних версиях, чем Android 4.0, тогда ваш виджет должен сам предоставить этот отступ.

Когда вы создаете виджет с помощью меню «Файл»> «Создать»> «Виджет»> «AppWidget» , Android Studio создает два файла измерения. Xml, которые гарантируют, что ваш виджет всегда будет иметь правильные отступы, независимо от версии Android, на которой он установлен.

Вы найдете оба этих файла в папке res вашего проекта:

res / values ​​/ d imens.xml

Этот файл определяет 8 dpi отступа, который должен предоставлять ваш виджет при установке на уровне API 13 или более ранней версии.

1

<dimen name=»widget_margin»>8dp</dimen>

RES / значения-V14 / dimens.xml

Поскольку Android 4.0 и выше автоматически применяет заполнение к каждому виджету, любые дополнения, которые предоставляет ваш виджет, будут в дополнение к этому заполнению по умолчанию.

Чтобы обеспечить соответствие вашего виджета любым значкам приложений или другим виджетам, которые пользователь разместил на своем домашнем экране, этот файл измерения. Xml указывает, что ваш виджет не должен содержать дополнительных полей для Android 4.0 и выше:

1

<dimen name=»widget_margin»>0dp</dimen>

Это поле по умолчанию помогает визуально сбалансировать домашний экран, поэтому вам следует избегать его изменения — в конце концов, вы не хотите, чтобы ваш виджет был нечетным!

Макет вашего виджета уже ссылается на это значение измерения (android:padding="@dimen/widget_margin") поэтому будьте осторожны, чтобы не изменять эту строку при работе над макетом вашего виджета.

Несмотря на то, что эти размеры. XML- файлы — это самый простой способ убедиться , что ваш виджет всегда имеет правильное заполнение, если этот метод не подходит для вашего конкретного проекта, то одна из альтернатив — создать несколько фонов из девяти патчей с разными полями для уровня API 14. и выше, и уровень API 13 и ниже. Вы можете создавать девять патчей с помощью инструмента Draw 9-patch в Android Studio или с помощью специальной программы для редактирования графики, такой как Adobe Photoshop.

Манифест проекта

В файле AndroidManifest.xml вашего проекта необходимо зарегистрировать свой виджет в качестве BroadcastReceiver и указать поставщика виджетов и файл AppWidgetProviderInfo, который этот виджет должен использовать.

Если вы откроете манифест, вы увидите, что Android Studio уже добавила всю эту информацию для вас.

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

//The widget’s AppWidgetProvider;

<receiver android:name=».NewAppWidget»>

      <intent-filter>

//An intent filter for the android.appwidget.action.APPWIDGET_UPDATE action//

          <action android:name=»android.appwidget.action.APPWIDGET_UPDATE» />

      </intent-filter>

      <meta-data

          android:name=»android.appwidget.provider»

//The widget’s AppWidgetProviderInfo object//

          android:resource=»@xml/new_app_widget_info» />

  </receiver>

</application>

Ресурс выбора виджетов

Файл res / drawable / example_appwidget_preview.png является ресурсом для рисования, который представляет ваш виджет в средстве выбора виджетов.

Чтобы поощрить пользователей выбирать ваш виджет из всех доступных вариантов, этот чертеж должен отображать ваш виджет, правильно настроенный на рабочем столе и отображающий много полезного контента.

Когда вы создаете виджет с помощью меню «Файл»> «Создать»> «Виджет»> «AppWidget» , Android Studio автоматически создает предварительный просмотр ( example_appwidget_preview.png ).

Во второй части я покажу вам, как быстро и легко заменить этот набор инструментов с помощью встроенных инструментов Android Studio для создания собственного предварительного изображения.

Создание вашего макета

Теперь у нас есть обзор того, как эти файлы собираются вместе, чтобы создать виджет приложения, давайте расширим этот фундамент и создадим виджет, который будет больше, чем просто отображать слово « Пример» на синем фоне!

Мы добавим следующую функциональность в наш виджет:

  • TextView , отображающий метку идентификатора виджета приложения .
  • TextView который получает и отображает идентификатор для этого конкретного экземпляра виджета.
  • TextView который реагирует на события onClick , запуская браузер пользователя по умолчанию и загружая URL.

Хотя мы могли бы просто перетащить три TextViews из палитры Android Studio и поместить их на холст, если ваш виджет выглядит хорошо, пользователи с большей вероятностью разместят его на своем домашнем экране, поэтому давайте создадим некоторые ресурсы, которые придадут нашему виджету дополнительную визуальность. обжалованию.

Создайте фон виджета

Я собираюсь создать прямоугольник с закругленными углами, градиентным фоном и рамкой, который я буду использовать в качестве фона для своего виджета:

  • Удерживая клавишу Control, щелкните на папке для рисования вашего проекта и выберите « Создать»> «Файл доступных для рисования ресурсов» .
  • Назовите этот файл widget_background и нажмите OK .
  • Введите следующий код:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

<?xml version=»1.0″ encoding=»UTF-8″?>

http://schemas.android.com/apk/res/android»

  android:shape=»rectangle»>

  <stroke

      android:width=»1dp»

      android:color=»#ffffff» />

  <gradient

      android:angle=»225″

      android:endColor=»#00FFFFFF»

      android:startColor=»#DD000000″ />

  <corners

      android:topRightRadius=»10dp»

      android:topLeftRadius=»10dp»

      android:bottomRightRadius=»10dp»

      android:bottomLeftRadius=»10dp» />

</shape>

2. Создайте фон TextView

Затем создайте фигуру для использования в качестве фона для наших TextViews :

  • Удерживая клавишу Control, щелкните на папке для рисования вашего проекта и выберите « Создать»> «Файл доступных для рисования ресурсов» .
  • Назовите этот файл tvbackground и затем нажмите OK .
  • Введите следующий код:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

<?xml version=»1.0″ encoding=»utf-8″?>

http://schemas.android.com/apk/res/android»

  android:shape=»rectangle» >

  <stroke

      android:width=»1dp»

      android:color=»#000000″ />

  <solid android:color=»#FFFFFFFF» />

  <corners

      android:topRightRadius=»15dp»

      android:topLeftRadius=»15dp»

      android:bottomRightRadius=»15dp»

      android:bottomLeftRadius=»15dp» />

</shape>

3. Создайте несколько стилей

Я также собираюсь использовать следующие стили:

  • widget_text . Смелый эффект, который я буду применять к тексту виджета.
  • widget_views . Различные поля и отступы, которые я буду применять к моим TextViews .

Откройте файл styles.xml вашего проекта и добавьте следующее:

01

02

03

04

05

06

07

08

09

10

11

<style name=»widget_views» parent=»@android:style/Widget»>

      <item name=»android:padding»>8dp</item>

      <item name=»android:layout_marginTop»>12dp</item>

      <item name=»android:layout_marginLeft»>12dp</item>

      <item name=»android:layout_marginRight»>12dp</item>

      <item name=»android:textStyle»>bold</item>

  </style>

<style name=»widget_text» parent=»@android:style/Widget»>

  <item name=»android:textStyle»>bold</item>

</style>

4. Создайте свой макет!

Теперь, когда все наши ресурсы готовы, мы можем создать макет нашего виджета. Откройте файл new_app_widget.xml и добавьте следующее:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

<LinearLayout xmlns:android=»http://schemas.android.com/apk/res/android»

  android:layout_width=»match_parent»

  android:layout_height=»match_parent»

  android:padding=»@dimen/widget_margin»

  android:background=»@drawable/widget_background»

  android:orientation=»vertical» >

  <LinearLayout

      android:background=»@drawable/tvbackground»

      style=»@style/widget_views»

      android:layout_width=»match_parent»

      android:layout_height=»wrap_content»

      android:orientation=»horizontal»>

      <TextView

          android:id=»@+id/id_label»

          android:layout_width=»wrap_content»

          android:layout_height=»wrap_content»

          android:text=»@string/widget_id»

          style=»@style/widget_text» />

      <TextView

          android:id=»@+id/id_value»

          android:layout_width=»wrap_content»

          android:layout_height=»wrap_content»

          android:text=».»

          style=»@style/widget_text» />

  </LinearLayout>

  <TextView

      android:id=»@+id/launch_url»

      style=»@style/widget_views»

      android:layout_width=»wrap_content»

      android:layout_height=»wrap_content»

      android:text=»@string/URL»

      android:background=»@drawable/tvbackground»/>

</LinearLayout>

Наконец, откройте файл strings.xml и определите строковые ресурсы, на которые мы ссылались в нашем макете:

1

2

3

4

5

<resources>

  <string name=»app_name»>Widget</string>

  <string name=»widget_id»>App Widget IDu0020</string>

  <string name=»URL»>Tap to launch URL</string>

</resources>

Вкладка « Дизайн » в Android Studio поможет вам работать более эффективно, предварительно просмотрев, как ваш макет будет отображаться на разных устройствах. Переход на вкладку « Дизайн » гораздо проще, чем запускать проект на устройстве Android каждый раз, когда вы вносите изменения в макет.

К сожалению, Android Studio не предоставляет выделенную обложку виджета, поэтому по умолчанию макет вашего виджета отображается так же, как обычная активность, которая не дает лучшего представления о том, как ваш виджет будет выглядеть на домашнем экране пользователя.

Одним из возможных путей решения этой проблемы является визуализация макета с использованием оболочки Android Wear (Square) , которая сопоставима с размером и формой виджета приложения Android:

  • Убедитесь, что выбрана вкладка « Устройство » в Android Studio.
  • Откройте раскрывающийся список устройств .
  • Выберите 280 x 280, hdpi (квадрат) в раскрывающемся меню.

Попробуйте отрисовать макет виджета, используя скин Android Wear Square

Создать функциональность виджета

Теперь, когда наш виджет выглядит, пришло время дать ему некоторую функциональность:

  • Получить и отобразить данные. Каждому экземпляру виджета присваивается идентификатор при добавлении на хост виджетов приложений. Этот идентификатор сохраняется в течение всего жизненного цикла виджета и будет полностью уникальным для этого экземпляра виджета, даже если пользователь добавляет несколько экземпляров одного и того же виджета на свой домашний экран.
  • Добавить действие. Мы создадим OnClickListener который запускает браузер пользователя по умолчанию и загружает URL.

Откройте файл поставщика виджетов ( NewAppWidget.java ) и удалите строку, которая извлекает строковый ресурс appwidget_text :

01

02

03

04

05

06

07

08

09

10

11

12

static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,

                          int appWidgetId) {

//Delete the following line//

  CharSequence widgetText = context.getString(R.string.appwidget_text);

  RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

  views.setTextViewText(R.id.appwidget_text, widgetText);

  appWidgetManager.updateAppWidget(appWidgetId, views);

}

В блоке updateAppWidget нам теперь нужно обновить местозаполнитель R.id.id_value уникальный идентификатор виджета:

1

2

RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

     views.setTextViewText(R.id.id_value, String.valueOf(appWidgetId));

Нам также необходимо создать объект Intent, содержащий URL-адрес, который должен загружаться всякий раз, когда пользователь взаимодействует с этим TextView .

1

2

3

4

5

6

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(«https://code.tutsplus.com/»));

      PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

//Attach an OnClickListener to our “launch_url” button, using setOnClickPendingIntent//

      views.setOnClickPendingIntent(R.id.launch_url, pendingIntent);

Вот полный файл поставщика виджетов:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

import android.appwidget.AppWidgetManager;

import android.appwidget.AppWidgetProvider;

import android.content.Context;

import android.widget.RemoteViews;

import android.app.PendingIntent;

import android.content.Intent;

import android.net.Uri;

public class NewAppWidget extends AppWidgetProvider {

  static void updateAppWidget(Context context,

                              AppWidgetManager appWidgetManager,

                              int appWidgetId) {

//Instantiate the RemoteViews object//

      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

//Update your app’s text, using the setTextViewText method of the RemoteViews class//

      views.setTextViewText(R.id.id_value, String.valueOf(appWidgetId));

//Register the OnClickListener//

      Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(«https://code.tutsplus.com/»));

      PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

      views.setOnClickPendingIntent(R.id.launch_url, pendingIntent);

      appWidgetManager.updateAppWidget(appWidgetId, views);

  }

  @Override

  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

      //Update all instances of this widget//

      for (int appWidgetId : appWidgetIds) {

          updateAppWidget(context, appWidgetManager, appWidgetId);

      }

  }

}

Тестирование виджета

Пришло время проверить этот виджет!

  • Установите обновленный проект на ваше устройство Android.
  • Чтобы убедиться, что вы видите последнюю версию этого виджета, удалите все существующие экземпляры виджета с рабочего стола.
  • Нажмите любой пустой раздел на главном экране, а затем выберите свой виджет из средства выбора виджетов.
  • Переместите и измените размер виджета по желанию.

Поместите свой виджет приложения Android в тесте

  • Убедитесь, что виджет реагирует на события пользовательского ввода, выбрав Коснитесь, чтобы запустить URL TextView . Виджет приложения должен ответить, запустив браузер по умолчанию и загрузив URL.

Если вы следовали этому руководству, то на данный момент у вас есть полностью работающий виджет, который демонстрирует многие основные концепции виджетов приложений Android. Вы также можете скачать готовый проект из нашего репозитория GitHub .

Вывод

В этом посте мы рассмотрели все файлы, необходимые для доставки виджета приложения Android, прежде чем создавать виджет, который извлекает и отображает некоторые уникальные данные и реагирует на события пользовательского ввода.

В настоящее время в нашем виджете все еще отсутствует одна важная функциональность: он никогда не отображает никакой новой информации! В следующем посте мы дадим этому виджету возможность извлекать и отображать новые данные автоматически, на основе установленного расписания и в прямой реакции на события пользовательского ввода.

А пока посмотрите другие наши замечательные посты о разработке приложений для Android здесь, на Envato Tuts +!

  • Android SDK

    Что такое мгновенные приложения для Android?

  • Android SDK

    Создание доступных приложений для Android

  • Android SDK

    Создание интерфейса с вкладками «Дизайн материала» в приложении для Android

  • Android SDK

    Совет: создайте пользовательскую плитку быстрых настроек для Android

    Ашраф Хатхибелагал

В этом уроке:

— создаем простой виджет
— разбираемся в его Lifecycle

Добрались таки и до этой долгожданной темы. Вообще, интересно было бы глянуть статистику, какое количество из всех существующих приложений содержит в себе виджеты. Подозреваю, что не чаще, чем одно из десяти. Возможно, ближайшие несколько уроков эту статистику изменят  )

Для понимания темы виджетов желательно знать, что такое BroadcastReceiver. Я о нем упоминал в Уроках 96 и 100. Это просто слушатель, который регистрируется в системе, ловит с помощью настроенного Intent Filter сообщения (Intent) и выполняет какой-либо код. Почему-то не сделал я отдельного урока по нему. Но, думаю, еще сделаю. Есть там свои интересные особенности, о которых можно поговорить.

Думаю, нет особой необходимости подробно объяснять, что такое виджеты. Все их видели на своих девайсах. Это что-то типа мини-приложений расположенных на рабочем столе (Home). Они позволяют просмотреть какую-либо информацию из основных приложений, либо повлиять на поведение этих приложений. В качестве примера можно привести – прогноз погоды, текущее время, баланс какого-либо счета, список сообщений в различных мессенджерах, управление состоянием WiFi/3G/GPS/Bluetooth, яркость экрана и т.д. и т.п. В этом уроке сделаем простейший виджет, который отобразит статичный текст.

Чтобы создать простейший виджет нам понадобятся три детали:

1) Layout-файл.

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

FrameLayout
LinearLayout
RelativeLayout
GridLayout

AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView
ViewFlipper
ListView
GridView
StackView
AdapterViewFlipper

2) XML-файл c метаданными

В нем задаются различные характеристики виджета. Мы пока что укажем следующие параметры:

— layout-файл (из п.1.), чтобы виджет знал, как он будет выглядеть
— размер виджета, чтобы виджет знал, сколько места он должен занять на экране
— интервал обновления, чтобы система знала, как часто ей надо будет обновлять виджет

3) Класс, наследующий AppWidgetProvider. В этом классе нам надо будет реализовать Lifecycle методы виджета.

Давайте создадим три этих детали. Activity нам не понадобится, поэтому не забудьте убрать галку Create Activity в визарде создания нового проекта

Создадим проект без Activity:

Project name: P1171_SimpleWidget
Build Target: Android 2.3.3
Application name: SimpleWidget
Package name: ru.startandroid.develop.p1171simplewidget

Добавим строки в strings.xml:

<string name="widget_name">My first widget</string>
<string name="widget_text">Text in widget</string>

Создаем layout-файл widget.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:orientation="vertical">
	<TextView
		android:id="@+id/tv"
		android:layout_width="match_parent"
		android:layout_height="match_parent"
		android:background="#6600ff00"
		android:gravity="center"
		android:text="@string/widget_text"
		android:textColor="#000"
		android:textSize="18sp">
	</TextView>
</RelativeLayout>

RelativeLayout, а внутри зеленый TextView с текстом по центру. Т.е. виджет просто будет показывать текст на зеленом фоне.

Создаем файл метаданных res/xml/widget_metadata.xml:

<appwidget-provider
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:initialLayout="@layout/widget"
	android:minHeight="40dp"
	android:minWidth="110dp"
	android:updatePeriodMillis="2400000">
</appwidget-provider>

В атрибуте initialLayout указываем layout-файл для виджета.

Атрибуты minHeight и minWidth содержат минимальные размеры виджета по высоте и ширине.

Есть определенный алгоритм расчета этих цифр. Как вы наверняка замечали, при размещении виджета, экран делится на ячейки, и виджет занимает одну или несколько из этих ячеек по ширине и высоте. Чтобы конвертнуть ячейки в dp, используется формула 70 * n – 30, где n – это количество ячеек. Т.е. если мы, например, хотим, чтобы наш виджет занимал 2 ячейки в ширину и 1 в высоту, мы высчитываем ширину = 70 * 2 – 30 = 110 и высоту = 70 * 1 – 30 = 40. Эти полученные значения и будем использовать в атрибутах minWidth  и minHeight.

Атрибут updatePeriodMillis содержит количество миллисекунд. Это интервал обновления виджета. Насколько я понял хелп, указать мы тут можем хоть 5 секунд, но чаще, чем раз в 30 минут (1 800 000) виджет обновляться все равно не будет — это системное ограничение. Давайте пока что поставим интервал 40 минут (2 400 000). В следующих уроках мы разберемся, как самим обновлять виджет с необходимым интервалом.

Осталось создать класс, наследующий AppWidgetProvider.

package ru.startandroid.develop.p1171simplewidget;

import java.util.Arrays;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.util.Log;

public class MyWidget extends AppWidgetProvider {

  final String LOG_TAG = "myLogs";

  @Override
  public void onEnabled(Context context) {
    super.onEnabled(context);
    Log.d(LOG_TAG, "onEnabled");
  }

  @Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager,
      int[] appWidgetIds) {
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    Log.d(LOG_TAG, "onUpdate " + Arrays.toString(appWidgetIds));
  }

  @Override
  public void onDeleted(Context context, int[] appWidgetIds) {
    super.onDeleted(context, appWidgetIds);
    Log.d(LOG_TAG, "onDeleted " + Arrays.toString(appWidgetIds));
  }

  @Override
  public void onDisabled(Context context) {
    super.onDisabled(context);
    Log.d(LOG_TAG, "onDisabled");
  }

}

onEnabled вызывается системой при создании первого экземпляра виджета (мы ведь можем добавить в Home несколько экземпляров одного и того же виджета).

onUpdate вызывается при обновлении виджета. На вход, кроме контекста, метод получает объект AppWidgetManager и список ID экземпляров виджетов, которые обновляются. Именно этот метод обычно содержит код, который обновляет содержимое виджета. Для этого нам нужен будет AppWidgetManager, который мы получаем на вход.

onDeleted вызывается при удалении каждого экземпляра виджета. На вход, кроме контекста, метод получает список ID экземпляров виджетов, которые удаляются.

onDisabled вызывается при удалении последнего экземпляра виджета.

Во всех методах выводим в лог одноименный текст и список ID для onUpdate и onDeleted.

Повторюсь — в onUpdate мы, по идее, должны накодить какое-то обновление виджета. Т.е. если наш виджет отображает, например, текущее время, то при очередном обновлении (вызове onUpdate) надо получать текущее время и передавать эту инфу в виджет для отображения. В этом уроке мы пока не будем с этим возиться.

Осталось немного подрисовать манифест. Добавьте туда ваш класс как Receiver

— укажите для него свои label и icon. Этот текст и эту иконку вы увидите в списке выбираемых виджетов, когда будете добавлять виджет на экран.

— настройте для него фильтр с action = android.appwidget.action.APPWIDGET_UPDATE

— добавьте метаданные с именем android.appwidget.provider и указанием файла метаданных xml/widget_metadata.xml в качестве ресурса

После этого секция receiver в манифесте должна получиться примерно такая:

<receiver
	android:name="MyWidget"
	android:icon="@android:drawable/star_big_on"
	android:label="@string/widget_name">
	<intent-filter>
		<action
			android:name="android.appwidget.action.APPWIDGET_UPDATE">
		</action>
	</intent-filter>
	<meta-data
		android:name="android.appwidget.provider"
		android:resource="@xml/widget_metadata">
	</meta-data>
</receiver>

Виджет готов. Все сохраняем и запускаем. Никаких Activity, разумеется, не всплывет. В консоли должен появиться текст:

P1171_SimpleWidgetbinP1171_SimpleWidget.apk installed on device
Done!

Открываем диалог создания виджета и видим в списке наш виджет с иконкой и текстом, которые мы указывали в манифесте для receiver.

Выбираем его и добавляем на экран.

Виджет появился, смотрим логи.

onEnabled
onUpdate [8]

Сработал onEnabled, т.к. мы добавили первый экземпляр виджета. И сразу после добавления, сработал метод onUpdate для этого экземпляра. Видим, что ему назначен ID = 8. (У вас, скорее всего, будет другой ID). Т.е. система добавила экземпляр виджета на экран и вызвала метод обновления с указанием ID экземпляра.

Добавим еще один экземпляр

Смотрим лог

onUpdate [9]

onEnabled не сработал, т.к. добавляемый экземпляр виджета уже не первый. onUpdate же снова отработал для нового добавленного экземпляра и получил на вход ID = 9.

Теперь давайте удалим с экрана два этих экземпляра виджета. Сначала второй. В логах увидим:

onDeleted [9]

Сработал onDeleted и получил на вход ID удаляемого экземпляра виджета.

Удаляем первый экземпляр. В логах:

onDeleted [8]
onDisabled

Снова сработал onDeleted — нас оповестили, что экземпляр виджета с ID=8 был удален. И сработал onDisabled, т.е. был удален последний экземпляр виджета, больше работающих экземпляров не осталось.

Наш виджет обновляется (получает вызов метода onUpdate) раз в 40 минут. Если кому не лень, добавьте снова пару виджетов на экран и подождите. Когда они снова обновятся, в логах это отразится.

Так создается и работает простой виджет. Пока остановимся на этом, чтобы уложились в голове схема создания виджета и его lifecycle-методы. Из интересного хотелось бы еще отметить пару вещей.

BroadcastReceiver

Класс AppWidgetProvider является расширением класса BroadcastReceiver (в манифесте мы его и прописали как Receiver). Он просто получает от системы сообщение в onReceive, определяет по значениям из Intent, какое именно событие произошло (добавление, удаление или обновление виджета), и вызывает соответствующий метод (onEnabled, onUpdate и пр.).

В манифесте мы для нашего Receiver-класса настроили фильтр с action, который ловит события update. Каким же образом этот Receiver ловит остальные события (например, удаление)? Хелп пишет об этом так:

The <intent-filter> element must include an <action> element with the android:name attribute. This attribute specifies that the AppWidgetProvider accepts the ACTION_APPWIDGET_UPDATE broadcast. This is the only broadcast that you must explicitly declare. The AppWidgetManager automatically sends all other App Widget broadcasts to the AppWidgetProvider as necessary.

Т.е. ACTION_APPWIDGET_UPDATE – это единственный action, который необходимо прописать явно. Остальные события AppWidgetManager каким-то образом сам доставит до нашего AppWidgetProvider-наследника.

Отступы

Если мы расположим рядом несколько экземпляров виджета, увидим следующую картину

Не очень приятное зрелище. Надо бы сделать отступ.

Добавим android:padding=»8dp» к RelativeLayout в нашем layout-файле

Сохраняем, запускаем.

Виджеты на экране поменялись автоматически и теперь выглядят более пристойно.

Кстати, для них сработал onUpdate, смотрите логи. В метод был передан массив ID всех работающих экземпляров виджета.

В Android 4.0 (API Level 14) и выше этот недостаток с отступами был устранен, и вручную делать отступы больше не надо. Давайте проверим. Уберите ранее добавленный в RelativeLayout отступ. И укажите в манифесте android:targetSdkVersion версию 14 (или выше), чтобы система знала, что можно использовать стандартные возможности, а не режим совместимости.

Все сохраняем, запускаем наш виджет на эмуляторе с 4.1. Добавим три экземпляра.

Система сама делает отступы между виджетами.

Получается для версий, ниже 4 надо делать отступ в layout, а для старших версий не надо. Хелп дает подсказку, как сделать так, чтобы ваш виджет корректно работал на всех версиях. Для этого используются квалификаторы версий.

В layout для RelativeLayuot указываете:

android:padding=»@dimen/widget_margin»

И создаете два файла.

res/values/dimens.xml с записью:

<dimen name="widget_margin">8dp</dimen>

и res/values-v14/dimens.xml с записью:

<dimen name="widget_margin">0dp</dimen>

В манифесте android:targetSdkVersion должен быть 14 или выше.

Таким образом, на старых версиях (без системного отступа) отступ будет 8dp, а на новых – 0dp и останется только системный отступ.

На следующем уроке:

— настраиваем виджет при размещении
— работаем с view-компонентами виджета при обновлении


Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance 

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня


Доброго времени суток… В этой статье разберём способ как создать свой собственный виджет для Android. Виджеты — это минимальные версии приложений, которые запускаются прямо на главном экране Android и могут быть чрезвычайно полезными. Большинство приложений в наши дни предлагают поддержку виджетов, вы можете легко получить к ним доступ прямо с домашнего экрана телефона. Однако, если вас не устраивает то, что доступно, вы всегда можете создать свои собственные виджеты для Android…

Содержание

  1. Как создать свои собственные виджеты для Android
  2. Как создать свой собственный виджет для Android
  3. Персонализация своего виджета
  4. Как создать свои собственные виджеты для Android — д обавление объектов
  5. Заключение

Добавить новые виджеты на экран Android довольно просто. Нажмите и удерживайте пустое место на главном экране. Ниже появится меню. Выберите ярлык «Виджеты». На некоторых моделях нужно сделать свайп двумя пальцами по экрану телефона…

Как создать свои собственные виджеты для Android

Вы попадете в список доступных виджетов вашего смартфона. Большинство приложений предлагают несколько вариантов. Выберите виджет, который хотите использовать, затем нажмите на него и перетащите на главный экран…

Как создать свои собственные виджеты для Android

Некоторые виджеты предлагают параметры настроек, которые позволяют персонализировать их…

Как создать свой собственный виджет для Android

Вы можете создать свой собственный виджет с помощью сторонних приложений. Одним из таких приложений является KWGT Kustom Widget Maker. Для этой статьи я буду использовать простой виджет…

Как создать свой собственный виджет для Android

Приложение также включает в себя библиотеку встроенных шаблонов виджетов, которые вы можете использовать или изменять в соответствии с вашими потребностями. Поэтому, если не хотите создавать новый виджет с нуля, можете просто воспользоваться тем, что вам предоставляет приложение…

Персонализация своего виджета

Вызовите список доступных виджетов на вашем устройстве, как было написано выше. Прокрутите вниз, пока не найдете шаблоны виджетов KWGT, и выберите виджет из опций…

Как создать свой собственный виджет для Android1

Перетащите его на главный экран…

Как создать свой собственный виджет для Android2

Нажмите на пустой виджет, чтобы открыть его в приложении KWGT, затем нажмите на кнопку «Создать»…

Как создать свой собственный виджет для Android3

Вы попадёте в раздел редактирования, в котором есть шесть вкладок: «Элементы», «Фон», «Слой», «Глобальные элементы», «Ярлыки» и «Сенсорный экран». Каждая вкладка позволяет вам настроить определенный аспект виджета…

Как создать свой собственный виджет для Android4

В настоящее время ваш виджет представляет собой просто пустой контейнер, который необходимо заполнить различными объектами. Но сначала вы должны добавить фон в свой новый виджет. Нажмите на вкладку фона и выберите цвет…

Читайте также Интересные статьи:

Как передавать YouTube-ролики с Android-устройства на компьютер

Оптимизация Android — устройств

Как скачать и установить приложения на андроид устройства из Google Play на компьютер

В качестве альтернативы вы можете использовать изображение с вашего устройства…

Как создать свой собственный виджет для Android5

Как создать свои собственные виджеты для Android — добавление объектов

Затем нажмите «Элементы», для добавления элементов в свой виджет. Это кнопка «+» в правом верхнем углу…

Как создать свой собственный виджет для Android6

Вы попадёте на панель, где сможете выбрать различные объекты для добавления в виджет…

Как создать свой собственный виджет для Android7

После того, как изображение или текст было добавлено в виджет, вы можете настроить его как вам угодно, редактировать текст, цвет, расположение, шрифт и так далее…

Как создать свой собственный виджет для Android8

Вот такой простой виджет у меня получился…

Как создать свой собственный виджет для Android9

Заключение

KWGT Kustom Widget Maker — в этой программе есть огромное количество возможностей для тех пользователей, которые хотят поэкспериментировать над своим рабочим столом Android и создать свои собственные виджеты, а также сделать его действительно уникальным. В KWGT Kustom Widget Maker присутствуют макеты и дополнительные настройки для таких типов виджетов, как астрономическая информация, мировое время, батарея, погода, текстовые виджеты, состояние памяти, карты, аналоговые часы и многое, многое другое. Всё это можно настраивать: изменять шрифты, добавлять эффекты, размеры всех элементов или даже делать виджеты в 3D, добавлять анимации…

Since Android 1.5, application widgets have enabled users to get information, control apps, and perform crucial tasks, all from the comfort of their homescreens.

In this two-part series, I’ll be showing you how to provide a better user experience by adding an application widget to your Android projects.

By the end of the series, you’ll have created a widget that:

  • Displays multiple sets of data.
  • Performs a unique action when the user interacts with a specific View within that widget’s layout.
  • Updates automatically whenever a set period of time has elapsed.
  • Updates with new data in response to user interaction.

In this first post, we’ll be using Android Studio’s built-in tools to quickly and easily generate all the files required to deliver any Android application widget. We’ll then expand on this foundation to create a widget that retrieves and displays data and responds to onClick events.

What Are Application Widgets?

An application widget is a lightweight, miniature app that typically falls into one of the following categories:  

  • Information widget. A non-scrollable widget that displays important information, such as a weather or clock widget.
  • Collection widgets. A scrollable widget that displays a series of related elements, such as a gallery of photos or articles from the same publication. Collection widgets are typically backed by a data source, such as an Array or database. A collection widget must include either a ListView, GridView, StackView, or an AdapterViewFlipper.
  • Control widgets. A widget that acts as a remote control for your application, allowing the user to trigger frequently used functions without necessarily having to launch your application. Applications that play music often provide a widget that lets the user play, pause, and skip tracks directly from their homescreen.
  • Hybrid widgets. Why restrict yourself to one category, when you can cherry-pick elements from multiple categories? Just be aware that mixing and matching can lead to a confusing user experience, so for the best results you should design your widget with a single category in mind and then add elements from other categories as required. For example, if you wanted to create a widget that displays today’s weather forecast but also allows users to view the forecast for different days and locations, then you should create an information widget and then add the necessary control elements afterwards.

In addition to the above functionality, most widgets respond to onClick events by launching their associated application, similar to an application shortcut, but they can also provide direct access to specific content within that application.

Application widgets must be placed inside an App Widget Host, most commonly the stock Android homescreen, although there are some third-party App Widget Hosts, such as the popular Nova Launcher and Apex Launcher.

Throughout this series, I’ll be talking about widgets as something you place on the homescreen, but if you have a vague recollection of being able to place widgets on the lockscreen, then this wasn’t just some kind of wonderful dream! Between API levels 17 and 20, it was possible to place widgets on the homescreen or the lockscreen.

Since lockscreen widgets were deprecated in API level 21, in this series we’ll be creating a widget for the homescreen only.

Why Should I Create an Application Widget?

There are several reasons why you should consider adding an application widget to your latest Android project.

Easy Access to Important Information and Features

Widgets allow the user to view your app’s most important information, directly from their homescreen. For example, if you’ve developed a calendar app then you might create a widget that displays details about the user’s next appointment. This is far more convenient than forcing the user to launch your app and potentially navigate multiple screens, just to retrieve the same information.

If you develop a control widget (or a hybrid widget with control elements) then the user can also complete tasks directly from their homescreen. Continuing with our calendar example, your widget might allow the user to create, edit and cancel appointments, potentially without even having to launch your app. This has the potential to remove multiple navigation steps from some of your app’s most important tasks, which can only have a positive impact on the user experience!

Direct Access to All of Your App’s Most Important Screens

Tapping a widget typically takes the user to the top level of the associated application, similar to an application shortcut. However, unlike app shortcuts, widgets can link to specific areas within the associated application. For example, tapping a widget’s New email received notification might launch the application with the new message already selected, while tapping Create new email might take them directly to your app’s ComposeEmail Activity.

By embedding multiple links in your widget’s layout, you can provide convenient, one-tap access to all of your app’s most important Activities.

Create a Loyal, Engaged User Base

As the whole Pokemon Go explosion and subsequent drop-off proved, getting a ton of people to download your app doesn’t automatically guarantee a loyal user base who will still be using your app days, weeks, or even months down the line.

Mobile users are a pretty fickle bunch, and with the memory available on your typical Android smartphone or tablet increasing all the time, it’s easy to lose track of the apps you’ve installed on your device. Chances are, if you pick up your Android smartphone or tablet now and swipe through the app drawer then you’ll discover at least one application that you’ve completely forgotten about.

By creating a widget that showcases all of your app’s most valuable information and features, you ensure that each time the user glances at their homescreen they’re reminded not only that your app exists, but also that it has some great content.

Adding an App Widget to Your Project

Even the most basic widget requires multiple classes and resources, but when you create a widget using Android Studio’s built-in tools, all of these files are generated for you. Since there’s no point in making Android development any harder than it needs to be, we’ll be using these tools to get a head-start on building our widget.

An application widget must always be tied to an underlying app, so create a new Android project with the settings of your choice.

Once Android Studio has built your project, select File > New > Widget > AppWidget from the Android Studio toolbar. This launches a Configure Component menu where you can define some of your widget’s initial settings.

Configure your widgets settings in Android StudioConfigure your widgets settings in Android StudioConfigure your widgets settings in Android Studio

Most of these options are pretty self-explanatory, but there are a few that are worth exploring in more detail.

Resizable (API 12+)

If a widget is resizable, then the user can increase or decrease the number of “cells” it occupies on their homescreen, by long-pressing the widget and then dragging the blue handles that appear around its outline.

Wherever possible, you should give your widget the ability to resize horizontally and vertically, as this will help your widget adapt to a range of screen configurations and homescreen setups. If a user has a seriously cluttered homescreen, then it may be impossible for your widget to even fit onto that homescreen, unless your widget is resizable.

If you do want to create a non-resizable widget, then open the Resizable dropdown menu and select either Only horizontally, Only vertically, or Not resizable.

Minimum Width and Height

The minimum width and height specifies the number of cells your widget will initially occupy when it’s placed on the homescreen.

For resizable widgets, this is the smallest the user can size your widget, so you can use these values to prevent users from shrinking your widget to the point where it becomes unusable.

If your widget isn’t resizable, then the minimum width and height values are your widget’s permanent width and height.

To increase a widget’s chances of fitting comfortably across a range of homescreens, it’s recommended that you never use anything larger than 4 by 4 for the minimum width and height values.

While the exact width and height of a homescreen “cell” vary between devices, you can get a rough estimate of how many DPIs (dots per inch) your widget will occupy using the following formula:

1
70 × number of cells -30

For example, if your widget is 2 x 3 cells:

1
70 x 2 - 30 = 110
2
70 x 3 - 30 = 180

This widget will occupy around 110 x 180 DPIs on the user’s homescreen. If these values don’t align with the dimensions of a particular device’s cells, then Android will automatically round your widget to the nearest cell size.

Review all the options in this menu and make any desired changes (I’m sticking with the defaults) and then click Finish.

Android Studio will now generate all the files and resources required to deliver a basic application widget. This widget isn’t exactly exciting (it’s basically just a blue block with the word Example written across it) but it is a functional widget that you can test on your device.

To test the widget:

  • Install your project on a physical Android device or AVD (Android Virtual Device).
  • Launch Android’s Widget Picker by pressing any empty space on the homescreen, and then tapping the word Widget that appears towards the bottom of the screen.
  • Swipe through the Widget Picker until you spot the blue Example widget.
  • Press down on this widget to drop it onto your homescreen.
  • Enter resize mode by pressing the widget until a set of blue handles appear, and then drag these handles to increase or decrease the number of cells that this widget occupies.

Test your widget on an Android Virtual DeviceTest your widget on an Android Virtual DeviceTest your widget on an Android Virtual Device

Exploring the Application Widget Files

This widget might not do all that much, but it includes all the classes and resources that we’ll be working on throughout the rest of this series, so let’s take a look at these files and the role they play in delivering an application widget.

NewAppWidget.java

The widget provider is a convenience class containing the methods used to programmatically interface with a widget via broadcast events. Under the hood, a widget is essentially just a BroadcastReceiver that can respond to various actions, such as the user placing a new widget instance on their homescreen.

Most notably, the app widget provider is where you’ll define your widget’s lifecycle methods, which either get called for every instance of the widget or for specific instances only.

Although we tend to think of a widget as a single entity that the user places on their homescreen once, there’s nothing to prevent them from creating multiple instances of the same widget. Maybe your widget is customisable, to the point where different instances can have significantly different functionality, or maybe the user just loves your widget so much that they want to plaster it all over their homescreen!  

Let’s take a look at the different lifecycle methods that you can implement in the widget provider class:

The onReceive Event

Android calls the onReceive() method on the registered BroadcastReceiver whenever the specified event occurs.

You typically won’t need to implement this method manually, as the AppWidgetProvider class automatically filters all widget broadcasts and delegates operations to the appropriate methods.

The onEnabled Event

The onEnabled() lifecycle method is called in response to ACTION_APPWIDGET_ENABLED, which is broadcast when the user adds the first instance of your widget to their homescreen. If the user creates two instances of your widget, then onEnabled() is called for the first instance, but not for the second.

This lifecycle method is where you perform any setup that only needs to occur once for all widget instances, such as creating a database or setting up a service.

Note that if the user deletes all instances of your widget from their device and then creates a new instance, then this is classed as the first instance, and consequently the onEnabled() method will be called once again.

The onAppWidgetOptionsChanged Event

This lifecycle method is called in response to ACTION_APPWIDGET_OPTIONS_CHANGED, which is broadcast when a widget instance is created and every time that widget is resized. You can use this method to reveal or hide content based on how the user sizes your widget, although this callback is only supported in Android 4.1 and higher.

The onUpdate Event

The onUpdate() lifecycle method is called every time:

  • The update interval has elapsed.
  • The user performs an action that triggers the onUpdate() method.
  • The user places a new instance of the widget on their homescreen (unless your widget contains a configuration Activity, which we’ll be covering in part two).

The onUpdate() lifecycle method is also called in response to ACTION_APPWIDGET_RESTORED, which is broadcast whenever a widget is restored from backup.

For most projects, the onUpdate() method will contain the bulk of the widget provider code, especially since it’s also where you register your widget’s event handlers.

The onDeleted Event

The onDeleted() method is called every time an instance of your widget is deleted from the App Widget Host, which triggers the system’s ACTION_APPWIDGET_DELETED broadcast.

The onDisabled Event

This method is called in response to the ACTION_APPWIDGET_DISABLED broadcast, which is sent when the last instance of your widget is removed from the App Widget Host. For example, if the user created three instances of your widget, then the onDisabled() method would only be called when the user removes the third and final instance from their homescreen.  

The onDisabled() lifecycle method is where you should clean up any resources you created in onEnabled(), so if you set up a database in onEnabled() then you’ll delete it in onDisabled().

The onRestored Event

The onRestored() method is called in response to ACTION_APPWIDGET_RESTORED, which is broadcast whenever an instance of an application widget is restored from backup. If you want to maintain any persistent data, then you’ll need to override this method and remap the previous AppWidgetIds to the new values, for example:

1
public void onRestored(Context context, int[] oldWidgetIds,
2
           int[] newWidgetIds) {
3
   }
4
}

If you open the NewAppWidget.java file that Android Studio generated automatically, then you’ll see that it already contains implementations for some of these widget lifecycle methods:

1
import android.appwidget.AppWidgetManager;
2
import android.appwidget.AppWidgetProvider;
3
import android.content.Context;
4
import android.widget.RemoteViews;
5

6
//All widgets extend the AppWidgetProvider class//

7

8
public class NewAppWidget extends AppWidgetProvider {
9

10
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
11
                              int appWidgetId) {
12

13
      CharSequence widgetText = context.getString(R.string.appwidget_text);
14

15
    //Load the layout resource file into a RemoteViews object//

16

17
      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
18
      views.setTextViewText(R.id.appwidget_text, widgetText);
19

20
 //Tell the AppWidgetManager about the updated RemoteViews object//

21

22
      appWidgetManager.updateAppWidget(appWidgetId, views);
23
  }
24

25
//Define the onUpdate lifecycle method//

26

27
  @Override
28
  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
29

30
//appWidgetIds is an array of IDs that identifies every instance of your widget, so this 

31
//particular onUpdate() method will update all instances of our application widget//

32

33
      for (int appWidgetId : appWidgetIds) {
34
          updateAppWidget(context, appWidgetManager, appWidgetId);
35
      }
36
  }
37

38
  @Override
39

40
//Define the onEnabled lifecycle method//

41

42
  public void onEnabled(Context context) {
43
      
44
      //To do//

45
  }
46

47
  @Override
48

49
//Define the onDisabled method//

50

51
  public void onDisabled(Context context) {
52
      
53
//To do//

54

55
  }
56
}

The Widget Layout File

The res/layout/new_app_widget.xml file defines our widget’s layout, which is currently just a blue background with the word Example written across it.  

The major difference between creating a layout for an Activity and creating a layout for a widget is that widget layouts must be based on RemoteViews, as this allows Android to display the layout in a process outside of your application (i.e. on the user’s homescreen).

RemoteViews don’t support every kind of layout or View, so when building a widget layout, you’re limited to the following types:

  • AnalogClock
  • Button
  • Chromometer
  • FrameLayout
  • GridLayout
  • ImageButton
  • ImageView
  • LinearLayout
  • ProgressBar
  • RelativeLayout
  • TextView
  • ViewStub

If you’re creating a collection widget, then you can also use the following types when your application is installed on Android 3.0 and higher:

  • AdapterViewFlipper
  • GridView
  • ListView
  • StackView
  • ViewFlipper

Subclasses and descendants of the above Views and classes are not supported.

Clicks and Swipes

To ensure users don’t accidentally interact with a widget while they’re navigating around their homescreen, widgets respond to onClick events only.

The exception is when the user removes a widget by dragging it towards their homescreen’s Uninstall action, as in this situation your widget will respond to the vertical swipe gesture. However, since this interaction is managed by the Android system, you don’t need to worry about implementing vertical swipe support in your application.

The Widget Info File

The res/xml/new_app_widget_info.xml file (also known as the AppWidgetProviderInfo file) defines a number of widget properties, including many of the settings you selected in Android Studio’s Configure Component menu, such as your widget’s minimum dimensions and whether it can be placed on the lockscreen.

The configuration file also specifies how frequently your widget requests new information from the App Widget update service. Deciding on this frequency requires you to strike a tricky balance: longer update intervals will help conserve the device’s battery, but place your intervals too far apart and your widget may display noticeably out-of-date information.

You should also be aware that the system will wake a sleeping device in order retrieve new information, so although updating your widget once every half an hour may not sound excessive, it could result in your widget waking the device once every 30 minutes, which is going to affect battery consumption.

If you open your project’s new_app_widget_info.xml file, then you’ll see that it already defines a number of widget properties, including the update interval.

1
<?xml version="1.0" encoding="utf-8"?>
2
<appwidget-provider xmlns:android="https://schemas.android.com/apk/res/android"
3

4
//The layout your widget should use when it’s placed on the lockscreen on supported devices//
5

6
  android:initialKeyguardLayout="@layout/new_app_widget"
7

8
//The layout your widget should use when it’s placed on the homescreen//
9

10
  android:initialLayout="@layout/new_app_widget"
11

12
//The minimum space your widget consumes, which is also its initial size//
13

14
  android:minHeight="40dp"
15
  android:minWidth="40dp"
16

17
//The drawable that represents your widget in the Widget Picker//
18

19
  android:previewImage="@drawable/example_appwidget_preview"
20

21
//Whether the widget can be resized horizontally, vertically, or along both axes, on Android 3.1 and higher//  
22

23
  android:resizeMode="horizontal|vertical"
24

25
//How frequently your widget should request new information from the app widget provider//
26

27
  android:updatePeriodMillis="86400000"
28

29
//Whether the widget can be placed on the homescreen, lockscreen (“keyguard”) or both.//
30
//On Android 5.0 and higher, home_screen is the only valid option//
31

32
  android:widgetCategory="home_screen"></appwidget-provider>

If you do give your users the option of placing your widget on the lockscreen, then bear in mind that the widget’s contents will be visible to anyone who so much as glances at the lockscreen. If your “default” layout contains any personal or potentially sensitive information, then you should provide an alternative layout for your widget to use when it’s placed on the lockscreen.

The res/values/dimens.xml File

Widgets don’t look their best when they’re pressed against one another, or when they extend to the very edge of the homescreen.

Whenever your widget is displayed on Android 4.0 or higher, the Android operating system automatically inserts some padding between the widget frame and the bounding box.

A widget consists of a bounding box frame widget margins widget padding and widget controlsA widget consists of a bounding box frame widget margins widget padding and widget controlsA widget consists of a bounding box frame widget margins widget padding and widget controls

If your app winds up on a device that’s running anything earlier than Android 4.0, then your widget needs to supply this padding itself.

When you create a widget using the File > New > Widget > AppWidget menu, Android Studio generates two dimens.xml files that guarantee your widget always has the correct padding, regardless of the version of Android it’s installed on.

You’ll find both of these files in your project’s res folder:

res/values/dimens.xml

This file defines the 8dpi of padding that your widget needs to provide whenever it’s installed on API level 13 or earlier.

1
<dimen name="widget_margin">8dp</dimen>

res/values-v14/dimens.xml

Since Android 4.0 and higher automatically applies padding to every widget, any padding that your widget provides will be in addition to this default padding.

To ensure your widget aligns with any app icons or other widgets that the user has placed on their homescreen, this dimens.xml file specifies that your widget should provide no additional margins for Android 4.0 and higher:

1
<dimen name="widget_margin">0dp</dimen>

This default margin helps to visually balance the homescreen, so you should avoid modifying it—you don’t want your widget to be the odd one out, after all!

Your widget’s layout already references this dimension value (android:padding="@dimen/widget_margin") so be careful not to change this line while working on your widget’s layout.

Although these dimens.xml files are the easiest way of ensuring your widget always has the correct padding, if this technique isn’t suitable for your particular project, then one alternative is to create multiple nine-patch backgrounds with different margins for API level 14 and higher, and API level 13 and lower. You can create nine-patches using Android Studio’s Draw 9-patch tool, or with a dedicated graphics editing program such as Adobe Photoshop.

The Project Manifest

In your project’s AndroidManifest.xml file, you need to register your widget as a BroadcastReceiver and specify the widget provider and the AppWidgetProviderInfo file that this widget should use.

If you open the manifest, you’ll see that Android Studio has already added all this information for you.

1
//The widget’s AppWidgetProvider; in this instance that’s NewAppWidget.java//
2

3
<receiver android:name=".NewAppWidget">
4
      <intent-filter>
5

6
//An intent filter for the android.appwidget.action.APPWIDGET_UPDATE action//
7

8
          <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
9
      </intent-filter>
10

11
      <meta-data
12
          android:name="android.appwidget.provider"
13

14
//The widget’s AppWidgetProviderInfo object//
15

16
          android:resource="@xml/new_app_widget_info" />
17

18
  </receiver>
19
</application>

Widget Picker Resource

The res/drawable/example_appwidget_preview.png file is the drawable resource that represents your widget in the Widget Picker.

To encourage users to select your widget from all the available options, this drawable should show your widget, properly configured on a homescreen and displaying lots of useful content.

When you create a widget using the File > New > Widget > AppWidget menu, Android Studio generates a preview drawable automatically (example_appwidget_preview.png).

In part two, I’ll be showing you how to quickly and easily replace this stock drawable, by using Android Studio’s built-in tools to generate your own preview image.

Building Your Layout

Now we have an overview of how these files come together to create an application widget, let’s expand on this foundation and create a widget that does more than just display the word Example on a blue background!

We’ll be adding the following functionality to our widget:

  • A TextView that displays an Application Widget ID label.
  • A TextView that retrieves and displays the ID for this particular widget instance.
  • A TextView that responds to onClick events by launching the user’s default browser and loading a URL.

While we could simply drag three TextViews from the Android Studio palette and drop them onto the canvas, if your widget looks good then users will be more likely to place it on their homescreen, so let’s create some resources that’ll give our widget extra visual appeal.

Create the Widget’s Background

I’m going to create a rectangle with rounded corners, a gradient background, and a border, which I’ll be using as the background for my widget:

  • Control-click your project’s drawable folder and select New > Drawable resource file.
  • Name this file widget_background and click OK.
  • Enter the following code:
1
<?xml version="1.0" encoding="UTF-8"?>
2
http://schemas.android.com/apk/res/android"
3
  android:shape="rectangle">
4

5
  <stroke
6
      android:width="1dp"
7
      android:color="#ffffff" />
8

9
  <gradient
10
      android:angle="225"
11
      android:endColor="#00FFFFFF"
12
      android:startColor="#DD000000" />
13

14
  <corners
15
      android:topRightRadius="10dp"
16
      android:topLeftRadius="10dp"
17
      android:bottomRightRadius="10dp"
18
      android:bottomLeftRadius="10dp" />
19
</shape>

2. Create the TextView Background

Next, create a shape to use as the background for our TextViews:

  • Control-click your project’s drawable folder and select New > Drawable resource file.
  • Name this file tvbackground and then click OK.
  • Enter the following code:
1
<?xml version="1.0" encoding="utf-8"?>
2
http://schemas.android.com/apk/res/android"
3
  android:shape="rectangle" >
4

5
  <stroke
6
      android:width="1dp"
7
      android:color="#000000" />
8

9
  <solid android:color="#FFFFFFFF" />
10

11
  <corners
12
      android:topRightRadius="15dp"
13
      android:topLeftRadius="15dp"
14
      android:bottomRightRadius="15dp"
15
      android:bottomLeftRadius="15dp" />
16
</shape>

3. Create Some Styles

I’m also going to use the following styles:

  • widget_text. A bold effect that I’ll apply to the widget’s text.
  • widget_views. The various margins and padding that I’ll apply to my TextViews.

Open your project’s styles.xml file and add the following:

1
<style name="widget_views" parent="@android:style/Widget">
2
      <item name="android:padding">8dp</item>
3
      <item name="android:layout_marginTop">12dp</item>
4
      <item name="android:layout_marginLeft">12dp</item>
5
      <item name="android:layout_marginRight">12dp</item>
6
      <item name="android:textStyle">bold</item>
7
  </style>
8

9
<style name="widget_text" parent="@android:style/Widget">
10
  <item name="android:textStyle">bold</item>
11
</style>

4. Build Your Layout!

Now that all our resources are in place, we can create our widget’s layout. Open the new_app_widget.xml file and add the following:

1
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2
  android:layout_width="match_parent"
3
  android:layout_height="match_parent"
4
  android:padding="@dimen/widget_margin"
5
  android:background="@drawable/widget_background"
6
  android:orientation="vertical" >
7

8
  <LinearLayout
9
      android:background="@drawable/tvbackground"
10
      style="@style/widget_views"
11
      android:layout_width="match_parent"
12
      android:layout_height="wrap_content"
13
      android:orientation="horizontal">
14

15
      <TextView
16
          android:id="@+id/id_label"
17
          android:layout_width="wrap_content"
18
          android:layout_height="wrap_content"
19
          android:text="@string/widget_id"
20
          style="@style/widget_text" />
21

22
      <TextView
23
          android:id="@+id/id_value"
24
          android:layout_width="wrap_content"
25
          android:layout_height="wrap_content"
26
          android:text="."
27
          style="@style/widget_text" />
28
  </LinearLayout>
29

30
  <TextView
31
      android:id="@+id/launch_url"
32
      style="@style/widget_views"
33
      android:layout_width="wrap_content"
34
      android:layout_height="wrap_content"
35
      android:text="@string/URL"
36
      android:background="@drawable/tvbackground"/>
37
</LinearLayout>

Finally, open the strings.xml file and define the string resources that we referenced in our layout:

1
<resources>
2
  <string name="app_name">Widget</string>
3
  <string name="widget_id">App Widget IDu0020</string>
4
  <string name="URL">Tap to launch URL</string>
5
</resources>

Android Studio’s Design tab helps you work more efficiently, by previewing how your layout will render across a range of devices. Switching to the Design tab is far easier than running your project on an Android device every single time you make a change to your layout.

Frustratingly, Android Studio doesn’t supply a dedicated widget skin, so by default your widget’s layout is rendered just like a regular Activity, which doesn’t provide the best insight into how your widget will look on the user’s homescreen.

One potential workaround is to render your layout using the Android Wear (Square) skin, which is comparable to the size and shape of an Android application widget:

  • Make sure Android Studio’s Device tab is selected.
  • Open the Device dropdown.
  • Select 280 x 280, hdpi (Square) from the dropdown menu.

Try rendering your widget layout using the Android Wear Square skinTry rendering your widget layout using the Android Wear Square skinTry rendering your widget layout using the Android Wear Square skin

Create the Widget Functionality

Now that our widget looks the part, it’s time to give it some functionality:

  • Retrieve and display data. Every instance of a widget is assigned an ID when it’s added to the App Widget Host. This ID persists across the widget’s lifecycle and will be completely unique to that widget instance, even if the user adds multiple instances of the same widget to their homescreen.
  • Add an action. We’ll create an OnClickListener that launches the user’s default browser and loads a URL.

Open the widget provider file (NewAppWidget.java) and delete the line that retrieves the appwidget_text string resource:

1
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
2
                          int appWidgetId) {
3

4
//Delete the following line//

5

6
  CharSequence widgetText = context.getString(R.string.appwidget_text);
7
  RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
8
  views.setTextViewText(R.id.appwidget_text, widgetText);
9

10
  appWidgetManager.updateAppWidget(appWidgetId, views);
11

12
}

In the updateAppWidget block, we now need to update the R.id.id_value placeholder with the widget’s unique ID:

1
  RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
2
      views.setTextViewText(R.id.id_value, String.valueOf(appWidgetId));

We also need to create an Intent object containing the URL that should load whenever the user interacts with this TextView.

1
      Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://code.tutsplus.com/"));
2
      PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
3

4
//Attach an OnClickListener to our “launch_url” button, using setOnClickPendingIntent//

5

6
      views.setOnClickPendingIntent(R.id.launch_url, pendingIntent);

Here’s the complete widget provider file:

1
import android.appwidget.AppWidgetManager;
2
import android.appwidget.AppWidgetProvider;
3
import android.content.Context;
4
import android.widget.RemoteViews;
5
import android.app.PendingIntent;
6
import android.content.Intent;
7
import android.net.Uri;
8

9
public class NewAppWidget extends AppWidgetProvider {
10

11
  static void updateAppWidget(Context context,
12

13
                              AppWidgetManager appWidgetManager,
14

15
                              int appWidgetId) {
16

17
//Instantiate the RemoteViews object//

18

19
      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
20

21
//Update your app’s text, using the setTextViewText method of the RemoteViews class//

22

23
      views.setTextViewText(R.id.id_value, String.valueOf(appWidgetId));
24

25
//Register the OnClickListener//

26

27
      Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://code.tutsplus.com/"));
28
      PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
29
      views.setOnClickPendingIntent(R.id.launch_url, pendingIntent);
30
      appWidgetManager.updateAppWidget(appWidgetId, views);
31

32
  }
33

34
  @Override
35
  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
36

37
      //Update all instances of this widget//

38

39
      for (int appWidgetId : appWidgetIds) {
40
          updateAppWidget(context, appWidgetManager, appWidgetId);
41
      }
42
  }
43
}

Testing the Widget

It’s time to put this widget to the test!

  • Install the updated project on your Android device.
  • To ensure you’re seeing the latest version of this widget, remove any existing widget instances from your homescreen.
  • Press any empty section of the homescreen, and then select your widget from the Widget Picker.
  • Reposition and resize the widget as desired.

Put your Android application widget to the testPut your Android application widget to the testPut your Android application widget to the test

  • Check that the widget responds to user input events, by selecting the Tap to launch URL TextView. The application widget should respond by launching your default browser and loading a URL.

If you’ve been following along with this tutorial, then at this point you have a fully functioning widget that demonstrates many of the core concepts of Android application widgets. You can also download the finished project from our GitHub repo.

Conclusion

In this post we examined all the files required to deliver an Android application widget, before building a widget that retrieves and displays some unique data and responds to user input events.

Currently, there’s one major piece of functionality still missing from our widget: it never displays any new information! In the next post, we’ll give this widget the ability to retrieve and display new data automatically, based on a set schedule, and in direct response to user input events.

In the meantime, check out some of our other great posts about Android app development here on Envato Tuts+!

Did you find this post useful?

Jessica Thornsby

Jessica Thornsby is a technical writer based in Sheffield. She writes about Android, Eclipse, Java, and all things open source. She is the co-author of iWork: The Missing Manual, and the author of Android UI Design.

Понравилась статья? Поделить с друзьями:
  • Как написать свой веб сервер
  • Как написать свой брут
  • Как написать свой браузер на python
  • Как написать свой браузер на java
  • Как написать свой блокнот