As seções a seguir descrevem como criar um widget de app básico com o Glance.
Declarar o AppWidget no manifesto
Depois de concluir as etapas de configuração, declare o AppWidget e os
metadados dele no app.
Estenda o receptor
AppWidgetdeGlanceAppWidgetReceiver:class MyAppWidgetReceiver : GlanceAppWidgetReceiver() { override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget") }
Registre o provedor do widget de app no arquivo
AndroidManifest.xmle no arquivo de metadados associado:<receiver android:name=".glance.MyReceiver" 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/my_app_widget_info" /> </receiver>
Adicionar os metadados AppWidgetProviderInfo
Em seguida, siga o guia Criar um widget para criar e definir as informações do widget de app
no arquivo @xml/my_app_widget_info.
A única diferença do Glance é que não há um XML initialLayout, mas é necessário definir um. Você pode usar o layout de carregamento predefinido fornecido na biblioteca:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>
Declarar o XML AppWidgetProviderInfo
O objeto AppWidgetProviderInfo define as qualidades essenciais do widget. Defina o AppWidgetProviderInfo no arquivo de recursos de metadados XML
(res/xml/my_app_widget_info.xml) dentro de um elemento <appwidget-provider>:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp"
android:minHeight="40dp"
android:targetCellWidth="1"
android:targetCellHeight="1"
android:maxResizeWidth="250dp"
android:maxResizeHeight="120dp"
android:updatePeriodMillis="86400000"
android:description="@string/example_appwidget_description"
android:previewLayout="@layout/example_appwidget_preview"
android:initialLayout="@layout/glance_default_loading_layout"
android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen"
android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>
Atributos de dimensionamento de widgets
A tela inicial padrão posiciona widgets na janela com base em uma grade de células com altura e largura definidas. A maioria das telas iniciais só permite que os widgets assumam tamanhos que sejam múltiplos inteiros das células da grade, por exemplo, duas células horizontalmente por três células verticalmente.
Os atributos de dimensionamento de widgets permitem especificar um tamanho padrão para o widget e fornecer limites inferiores e superiores no tamanho dele. Nesse contexto, o tamanho padrão de um widget é o tamanho que ele assume quando é adicionado à tela inicial pela primeira vez.
A tabela a seguir descreve os atributos <appwidget-provider> relacionados
ao dimensionamento de widgets:
| Atributos e descrição | |
|---|---|
targetCellWidth e
targetCellHeight (Android 12),
minWidth e minHeight |
targetCellWidth e
targetCellHeight, e minWidth e
minHeight. Assim, seu app poderá usar
minWidth e minHeight se o dispositivo do usuário
não oferecer suporte a targetCellWidth e
targetCellHeight. Se houver suporte, os
targetCellWidth e targetCellHeight atributos
terão precedência sobre os minWidth e minHeight
atributos.
|
minResizeWidth e
minResizeHeight |
Especifica o tamanho mínimo absoluto do widget. Esses valores especificam o
tamanho abaixo do qual o widget fica ilegível ou inutilizável. O uso
desses atributos permite que o usuário redimensione o widget para um tamanho menor
que o tamanho padrão. O atributo minResizeWidth é
ignorado se for maior que minWidth ou se o redimensionamento horizontal
não estiver ativado. Consulte
resizeMode. Da mesma forma, o
minResizeHeight atributo é ignorado se for maior que
minHeight ou se o redimensionamento vertical não estiver ativado. |
maxResizeWidth e
maxResizeHeight |
Especifica o tamanho máximo recomendado do widget. Se os valores não forem
um múltiplo das dimensões da célula da grade, eles serão arredondados para cima para o tamanho de célula mais próximo. O atributo maxResizeWidth é ignorado se for
menor que minWidth ou se o redimensionamento horizontal não estiver
ativado. Consulte resizeMode. Da mesma forma,
o atributo maxResizeHeight é ignorado se for menor
que minHeight ou se o redimensionamento vertical não estiver ativado.
Introduzido no Android 12. |
resizeMode |
Especifica as regras pelas quais um widget pode ser redimensionado. Você pode usar esse
atributo para permitir o redimensionamento dos widgets da tela inicial: na horizontal, vertical,
ou nos dois eixos. Os usuários tocam em um widget e o mantêm pressionado para mostrar as alças de redimensionamento,
em seguida, arrastam as alças horizontais ou verticais para mudar o tamanho na
grade do layout. Os valores do atributo resizeMode incluem
horizontal, vertical e none. Para
declarar um widget como redimensionável horizontal e verticalmente, use
horizontal|vertical. |
Exemplo
Para ilustrar como os atributos na tabela anterior afetam o dimensionamento do widget, considere as seguintes especificações:
- Uma célula da grade tem 30 dp de largura e 50 dp de altura.
- A seguinte especificação de atributo é fornecida:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="80dp"
android:minHeight="80dp"
android:targetCellWidth="2"
android:targetCellHeight="2"
android:minResizeWidth="40dp"
android:minResizeHeight="40dp"
android:maxResizeWidth="120dp"
android:maxResizeHeight="120dp"
android:resizeMode="horizontal|vertical" />
A partir do Android 12 :
Use os atributos targetCellWidth e targetCellHeight como o tamanho padrão do widget.
O tamanho do widget é 2x2 por padrão. O widget pode ser redimensionado para 2x1 ou até 4x3.
Android 11 e versões anteriores :
Use os atributos minWidth e minHeight para calcular o tamanho padrão do widget.
A largura padrão = Math.ceil(80 / 30) = 3
A altura padrão = Math.ceil(80 / 50) = 2
O tamanho do widget é 3x2 por padrão. O widget pode ser redimensionado para 2x1 ou até a tela cheia.
Outros atributos de widget
A tabela a seguir descreve os atributos <appwidget-provider> relacionados
a qualidades diferentes do dimensionamento de widgets.
| Atributos e descrição | |
|---|---|
updatePeriodMillis |
Define a frequência com que o framework do widget solicita uma atualização do
GlanceAppWidgetReceiver chamando o método de callback onUpdate(). Recomendamos atualizar com a menor frequência possível,
no máximo uma vez por hora, para economizar bateria.
Para mais detalhes, consulte a seção Quando atualizar widgets em Gerenciamento de estado do Glance. |
initialLayout |
Aponta para o recurso de layout que define o layout de carregamento do widget antes da renderização das composições da interface do Glance. Você pode usar o layout de carregamento predefinido fornecido na biblioteca: @layout/glance_default_loading_layout. |
configure |
Define a atividade de configuração que é iniciada quando o usuário adiciona o widget. Consulte o guia Implementar a atividade de configuração. |
description |
Especifica a descrição que o seletor de widgets vai mostrar para o widget. Introduzido no Android 12. |
previewLayout (Android 12) e previewImage (Android 11 e versões anteriores) |
|
autoAdvanceViewId |
Especifica o ID de visualização da subexibição do widget, que é avançado automaticamente pelo host do widget. |
widgetCategory |
Declara se o widget pode ser exibido na tela inicial
(home_screen), na tela de bloqueio (keyguard) ou nas duas. No Android 5.0 e versões mais recentes, apenas home_screen é válido. |
widgetFeatures |
Declara os recursos com suporte do widget. Por exemplo, se a configuração do widget for opcional, especifique configuration_optional e reconfigurable. |
Definir GlanceAppWidget
Crie uma nova classe que se estenda de
GlanceAppWidgete substitua o métodoprovideGlance. Esse é o método em que você pode carregar os dados necessários para renderizar o widget:class MyAppWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { // In this method, load data needed to render the AppWidget. // Use `withContext` to switch to another thread for long running // operations. provideContent { // create your AppWidget here Text("Hello World") } } }
Instancie-o no
glanceAppWidgetnoGlanceAppWidgetReceiver:class MyAppWidgetReceiver : GlanceAppWidgetReceiver() { // Let MyAppWidgetReceiver know which GlanceAppWidget to use override val glanceAppWidget: GlanceAppWidget = MyAppWidget() }
Você configurou um AppWidget usando o Glance.
Usar a classe GlanceAppWidgetReceiver para processar transmissões de widgets
O GlanceAppWidgetReceiver coordena transmissões de widgets e atualizações de estado da plataforma
estendendo o AppWidgetProvider subjacente. Ele recebe eventos da plataforma quando o widget é atualizado, excluído, ativado ou desativado, traduzindo-os em solicitações de ciclo de vida do Compose.
Declarar um widget no manifesto
Declare a subclasse GlanceAppWidgetReceiver como um broadcast receiver no arquivo AndroidManifest.xml:
<receiver android:name="MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/my_app_widget_info" />
</receiver>
O elemento <receiver> requer o atributo android:name, que especifica
a classe do receptor. O receptor precisa aceitar a ACTION_APPWIDGET_UPDATE
ação de transmissão dentro do <intent-filter>.
O elemento <meta-data> precisa identificar o nome como
android.appwidget.provider, e o atributo android:resource precisa apontar para
o recurso de metadados XML AppWidgetProviderInfo (@xml/my_app_widget_info).
Implementar a classe GlanceAppWidgetReceiver
No Glance, você estende GlanceAppWidgetReceiver em vez de AppWidgetProvider diretamente. Implemente-o vinculando o receptor à instância GlanceAppWidget. Os callbacks principais disponíveis no GlanceAppWidgetReceiver funcionam da seguinte maneira:
onUpdate(): substituído automaticamente pelo Glance para executar atualizações de composição. Se você substituironUpdatemanualmente, será necessário chamarsuper.onUpdatepara permitir que o Glance inicie threads de composição.onAppWidgetOptionsChanged(): chamado quando o widget é colocado ou redimensionado pela primeira vez. O Glance lê itens de pacote de opções em segundo plano para que o layout seja ajustado perfeitamente com base nas dimensões de execução.onDeleted(Context, IntArray): invocado sempre que uma instância de widget específica é excluída pelo usuário.onEnabled(Context): acionado quando a primeira instância do widget é criada. Excelente para executar migrações globais.onDisabled(Context): chamado quando a última instância ativa do provedor é removida.onReceive(Context, Intent): intercepta todas as transmissões da plataforma antes de métodos de callback específicos. É necessário garantir que qualquer lógica de receptor personalizada que você escreva chamesuper.onReceive(context, intent)e nunca chamegoAsync, já que o Glance encaminha o trabalho automaticamente de forma assíncrona.
Receber intents de transmissão de widgets
Em segundo plano, GlanceAppWidgetReceiver filtra e processa os seguintes intents de transmissão de widgets da plataforma:
ACTION_APPWIDGET_UPDATEACTION_APPWIDGET_DELETEDACTION_APPWIDGET_ENABLEDACTION_APPWIDGET_DISABLEDACTION_APPWIDGET_OPTIONS_CHANGED
Criar interface
O snippet a seguir demonstra como criar a interface:
/* Import Glance Composables In the event there is a name clash with the Compose classes of the same name, you may rename the imports per https://kotlinlang.org/docs/packages.html#imports using the `as` keyword. import androidx.glance.Button import androidx.glance.layout.Column import androidx.glance.layout.Row import androidx.glance.text.Text */ class MyAppWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { // Load data needed to render the AppWidget. // Use `withContext` to switch to another thread for long running // operations. provideContent { // create your AppWidget here MyContent() } } @Composable private fun MyContent() { Column( modifier = GlanceModifier.fillMaxSize(), verticalAlignment = Alignment.Top, horizontalAlignment = Alignment.CenterHorizontally ) { Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp)) Row(horizontalAlignment = Alignment.CenterHorizontally) { Button( text = "Home", onClick = actionStartActivity<MyActivity>() ) Button( text = "Work", onClick = actionStartActivity<MyActivity>() ) } } } }
O exemplo de código anterior faz o seguinte:
- No
Columnde nível superior, os itens são colocados verticalmente um após o outro. - O
Columnexpande o tamanho para corresponder ao espaço disponível (peloGlanceModifiere alinha o conteúdo à parte de cima (verticalAlignment) e o centraliza horizontalmente (horizontalAlignment). - O conteúdo da
Columné definido usando a lambda. A ordem é importante.- O primeiro item na
Columné um componenteTextcom12.dpde preenchimento. - O segundo item é uma
Row, em que os itens são colocados horizontalmente um após o outro, com doisButtonscentralizados horizontalmente (horizontalAlignment). A exibição final depende do espaço disponível. A imagem a seguir é um exemplo de como ela pode ser:
- O primeiro item na
É possível mudar os valores de alinhamento ou aplicar valores de modificador diferentes (como preenchimento) para mudar o posicionamento e o tamanho dos componentes. Consulte a documentação de referência para conferir uma lista completa de componentes, parâmetros e modificadores disponíveis para cada classe.
Implementar cantos arredondados
O Android 12 introduz parâmetros de sistema para personalizar os raios dos cantos dos widgets de app de forma dinâmica:
system_app_widget_background_radius: especifica o raio do canto do contêiner de plano de fundo do widget (nunca maior que 28 dp).- Raio interno:para evitar o recorte de conteúdo, calcule um raio proporcional para o conteúdo interno com base no contorno do plano de fundo do sistema:
systemRadiusValue - widgetPadding
No Glance, é possível aplicar propriedades de dimensionamento de raio de canto de forma dinâmica na composição usando GlanceModifier.cornerRadius(android.R.dimen.system_app_widget_background_radius).
Para compatibilidade com versões anteriores em dispositivos com o Android 11 (nível 30 da API) ou versões anteriores, implemente atributos personalizados e fallbacks de recursos de tema personalizados:
/values/attrs.xml<resources> <attr name="backgroundRadius" format="dimension" /> </resources>/values/styles.xml<resources> <style name="MyWidgetTheme"> <item name="backgroundRadius">@dimen/my_background_radius_dimen</item> </style> </resources>/values-31/styles.xml<resources> <style name="MyWidgetTheme" parent="@android:style/Theme.DeviceDefault.DayNight"> <item name="backgroundRadius">@android:dimen/system_app_widget_background_radius</item> </style> </resources>/drawable/my_widget_background.xml<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="?attr/backgroundRadius" /> </shape>