Android App Widgets Tutorial
Learn how to give your users fast access to the most important functions of your Android app, right from their home screen, using App Widgets. By Matei Suica.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Android App Widgets Tutorial
35 mins
- Getting started
- App widget anatomy
- User interface
- Resizability and preview
- Refreshing the widget
- Widget customisation
- Create your Widget
- Customizing the User Interface
- Thinking vertically
- Adding buttons
- Run your Widget
- Performing actions
- The RemoteViews class
- Updating the Widget
- Widget configuration
- Managing updates requests
- Update the widget manually
- Communicating via Service
- Making it personal
- Creating a preferences screen
- Know your limits
- Linking preferences to the widget
- Best practices
- Where to go from here
Widget customisation
In the case of Coffee Log, there are just three different type of coffees. But what if the user is not interested in Long coffee or they just want a different drink instead, or what if they want to simply change the quantity of grams. Or maybe the user wants to customise the background color of the Widget. As you’ll see, it’s possible to provide a configuration screen to allow all the needed customisation.
Create your Widget
Enough theory, now you can start creating your Widget. Creating a Widget requires the definition of some code and configuration files according to the specification defined by the Android platform.
Android Studio makes this process very easy, through the usage of a simple wizard, which you can access by selecting New\Widget\App widget from the File menu. You’ll see the following window:
Add the following input to the window:
- Class name:
CoffeeLoggerWidget
- Minimum Width (cells): 3
- Minimum Height (cells): 2
Here you can also see how it’s possible to define whether the Widget is resizable and what its possible destinations are. A Widget is usually part of the Home screen, but it could also part of the Keyguard, which is the screen that appears when the phone is locked.
Select Finish, and Android Studio will create three files for you:
-
CoffeeLoggerWidget.kt: this is a Kotlin class with the same name used in the wizard, and acts as the controller for the Widget. You’ll learn how to change this code in order to access the UI component through the
RemoteViews
class and how to receive and manage events from the Widget itself. -
coffee_logger_widget_info.xml: this is the configuration file we described earlier with information about the refresh rate, resizability, dimensions, etc. This is the file you’re going to edit in order to provide a configuration
Activity
for the Widget. - coffee_logger_widget.xml: this file contains the widget’s user interface layout.
It’s important to note where all these files are in the project structure:
In particular, you see how the configuration file has been created as an XML resource file.
As you’ll see later, the wizard also made some changes to the app AndroidManifest.xml file.
Customizing the User Interface
In order to customize the UI for the Widget, open coffee_logger_widget.xml in the app\res\layout folder. The Android Studio wizard generated the following layout that you need to update:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
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>
Remove the TextView
and replace the RelativeLayout
with a LinearLayout
. In Android Studio, you can do this by double-clicking on the old name and typing the new name in its place. After this change you should have this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#09C"
android:padding="@dimen/widget_margin">
</LinearLayout>
Note: You’re going to use styles that are already defined in the sample project. They contain text sizes and colors, heights, widths, alignments, and other style values. If you are curious about them, check out styles.xml in the res/values folder.
Note: You’re going to use styles that are already defined in the sample project. They contain text sizes and colors, heights, widths, alignments, and other style values. If you are curious about them, check out styles.xml in the res/values folder.
Next, add three more attributes to the LinearLayout
:
...
android:id="@+id/widget_layout"
android:orientation="vertical"
android:gravity="center"
...
The android:orientation
and android:gravity
attributes give the LinearLayout
information about how to align its content. Providing an id
is also important in case we need to get a reference to the layout in the Kotlin code.
To achieve rounded corners, change the android:background
attribute to @drawable/background
, a drawable available in the starter project. Now the root element of the layout looks like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/widget_margin">
</LinearLayout>
Thinking vertically
For the sake of aesthetics, the user interface should look good regardless of the Widget size. It’s best to have the Widget elements spread over the available space. There are many ways to achieve that, but you should go for the simplest which consists of adding some TextView
components that will expand in the remaining space between the rest of the elements.
Here’s a schematic of the layout you’ll create:
The green pattern will be a TextView
that expands vertically and the blue pattern will be a TextView
that expands horizontally. Keep this schematic in mind as you build the layout to understand why you add each element.
Note:If you’re tempted to fill the empty spaces using a Space
instead of TextView
, remember that a Widget has some UI restrictions and that a Space
is not one of the allowed components.
Note:If you’re tempted to fill the empty spaces using a Space
instead of TextView
, remember that a Widget has some UI restrictions and that a Space
is not one of the allowed components.
The first element in the LinearLayout
is a vertical space that you can define by adding this code as the first child:
<TextView style="@style/WidgetButtonVerticalSpace" />
Now you can add the TextView
components for the amout of coffee:
<TextView
android:id="@+id/appwidget_text"
style="@style/WidgetTextView.Big" />
<TextView
style="@style/WidgetTextView"
android:text="@string/grams" />
Then add another TextView
for the next vertical space before the buttons:
<TextView style="@style/WidgetButtonVerticalSpace" />
Notice that the first text view needs to have an id because you will need to change the text later on from the Kotlin code. The second one is fixed text. You’re using the predefined styles on the text views.
Next, add a container for the buttons as a LinearLayout
with horizontal orientation:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- Buttons go here -->
</LinearLayout>
Then a TextView
for the quote after the last vertical space.
<TextView style="@style/WidgetButtonVerticalSpace" />
<TextView
android:id="@+id/coffee_quote"
style="@style/WidgetQuote" />
Adding buttons
Now the green part of the layout is fnished and you have to deal with the blue part for the buttons following this schematic:
You’ve already created a container for them so you just need to start with a TextView
that expands horizontally and will keep the first button at a distance from the left margin:
<TextView style="@style/WidgetButtonHorizontalSpace" />
Then you can add the first button for smallest coffee in the world:
<LinearLayout
android:id="@+id/ristretto_button"
style="@style/WidgetBeverageButton" >
<ImageView
style="@style/WidgetButtonImage"
android:src="@drawable/ic_ristretto" />
<TextView
style="@style/WidgetButtonText"
android:text="@string/ristretto_short" />
</LinearLayout>
<TextView style="@style/WidgetButtonHorizontalSpace" />
Each button has a LinearLayout
that contains an ImageView
and a TextView
. After the button, you added another horizontally expanding TextView
to help the buttons spread.
Add the next button for Espresso:
<LinearLayout
android:id="@+id/espresso_button"
style="@style/WidgetBeverageButton">
<ImageView
style="@style/WidgetButtonImage"
android:src="@drawable/ic_espresso" />
<TextView
style="@style/WidgetButtonText"
android:text="@string/espresso_short" />
</LinearLayout>
<TextView style="@style/WidgetButtonHorizontalSpace" />
And the final button for the Long:
<LinearLayout
android:id="@+id/long_button"
style="@style/WidgetBeverageButton" >
<ImageView
style="@style/WidgetButtonImage"
android:src="@drawable/ic_long_coffee" />
<TextView
style="@style/WidgetButtonText"
android:text="@string/long_coffee_short" />
</LinearLayout>
<TextView style="@style/WidgetButtonHorizontalSpace" />
Phew! That was long but you’re done with the layout for the widget. :]