Blog Infos
Author
Published
Topics
Published

App widgets are miniature application views that can be embedded in the home screen of your device. Jetpack Glance is a library built on top of Jetpack Compose that allows you to build these widgets for Android.

In the above image you can see a weather widget.

In this other example, you can see a music app widget that allows you to control the music playback.

In this tutorial we’ll create a quotes widget.

Setup

Jetpack Glance was released in 2021 and as of now, it has a release candidate.

Before we start make sure you have Jetpack Compose enabled.

android {
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.1.0-beta03"
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Then include the dependencies for Glance.

dependencies {
    implementation "androidx.glance:glance:1.0.0-rc01"
    implementation "androidx.glance:glance-appwidget:1.0.0-rc01"
}

The first thing we need to do is to define an app widget provider. Create a file named app_widget_provider.xml inside res/xml.

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="100dp"
    android:minHeight="100dp" />

There are many attributes you can define, if you want to learn more about them you can read this documentation.

After that we need to create our widget.

class QuotesWidget : GlanceAppWidget() {

  override val stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition
      override suspend fun provideGlance(context: Context, id: GlanceId) {
          provideContent {
              Text(text = "Hello World!")
          }
      }
}

The main thing here is the provideGlance function, that’s where you define which composable you want displayed.

Make sure you import the composables from Glance. For example you need to use androidx.glance.text.Text instead of androidx.compose.material3.Text.

After that we need to declare our receiver.

class QuotesWidgetReceiver : GlanceAppWidgetReceiver() {
  
  override val glanceAppWidget: GlanceAppWidget = QuotesWidget()

}

Now go to your AndroidManifest and import the receiver you just declared.

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    
    <application ...>
        <receiver
            android:name=".QuotesWidgetReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/app_widget_provider" />
        </receiver>        
    </application>

</manifest>

If you don’t have an activity you need to modify Android Studio so it runs without one. First go to your run configuration.

Then select “Always install with package manager” and change “Launch:” to “Nothing”.

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

,

Take a look at Jetpack Glance

Jetpack Glance is the new shiny library in the Jetpack family for creating widgets. At first glance, it resembles a Jetpack Compose, but in many cases, it is really different. Learn those differences and create…
Watch Video

Take a look at Jetpack Glance

Piotr Prus
Android Developer

Take a look at Jetpack Glance

Piotr Prus
Android Developer

Take a look at Jetpack Glance

Piotr Prus
Android Developer

Jobs

After that you should be able to run the app. Open the widgets screen and find your widget there.

Now that we already have a widget, let’s add some functionality to it.

private val quotes = listOf(
    "Be yourself; everyone else is already taken. ― Oscar Wilde",
    "A room without books is like a body without a soul. ― Marcus Tullius Cicero",
    "You only live once, but if you do it right, once is enough. ― Mae West",
)

private val currentQuoteKey = stringPreferencesKey("currentQuote")

class QuotesWidget : GlanceAppWidget() {

    override val stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        provideContent {
            val preferences = currentState<Preferences>()
            val currentQuote = preferences[currentQuoteKey] ?: quotes.random()

            MaterialTheme {
                Box(
                    modifier = GlanceModifier
                        .background(Color.White)
                        .padding(16.dp)
                        .clickable(actionRunCallback<RefreshQuoteAction>())
                ) {
                    Text(text = currentQuote)
                }
            }
        }
    }

}

class RefreshQuoteAction : ActionCallback {

    override suspend fun onAction(
        context: Context,
        glanceId: GlanceId,
        parameters: ActionParameters
    ) {
        updateAppWidgetState(context, PreferencesGlanceStateDefinition, glanceId) { preferences ->
            preferences.toMutablePreferences().apply {
                this[currentQuoteKey] = quotes.random()
            }
        }
        QuotesWidget().update(context, glanceId)
    }
}

Run the widget again and you’ll see a quote. Tap the widget and it’ll display a different quote.

If you want to learn more about widgets you can follow the Android documentation.

Photo by Vincent LaVigna on Unsplash

 

This article was previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
In this part of our series on introducing Jetpack Compose into an existing project,…
READ MORE
blog
This is the second article in an article series that will discuss the dependency…
READ MORE
blog
Let’s suppose that for some reason we are interested in doing some tests with…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu