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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 5 of this article. Click here to view the first page.

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:

New Android component

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:

New files

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.

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:

Widget Schematic

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.

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:

Widget buttons

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. :]

Matei Suica

Contributors

Matei Suica

Author

Massimo Carli

Tech Editor

Joe Howard

Final Pass Editor

Over 300 content creators. Join our team.