manifesto, metadados
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 para o Glance é que não há XML initialLayout, mas você precisa 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 seu
widget. Defina o AppWidgetProviderInfo no arquivo de recurso 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 são múltiplos inteiros das células da grade. Por exemplo, duas células na horizontal por três na vertical.
Com os atributos de dimensionamento de widget, é possível especificar um tamanho padrão para o widget e fornecer limites inferiores e superiores para o 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 pode voltar a usar
minWidth e minHeight se o dispositivo do usuário
não for compatível com targetCellWidth e
targetCellHeight. Se compatíveis, os atributos
targetCellWidth e targetCellHeight
terão precedência sobre os atributos minWidth e minHeight.
|
minResizeWidth e
minResizeHeight |
Especifique o tamanho mínimo absoluto do widget. Esses valores especificam o tamanho abaixo do qual o widget fica ilegível ou inutilizável. Usar esses atributos permite que o usuário redimensione o widget para um tamanho menor que o 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 atributo
minResizeHeight é ignorado se for maior que
minHeight ou se o redimensionamento vertical não estiver ativado. |
maxResizeWidth e
maxResizeHeight |
Especifique o tamanho máximo recomendado do widget. Se os valores não forem múltiplos das dimensões da célula da grade, eles serão arredondados para cima até 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 será 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. É possível usar esse
atributo para permitir o redimensionamento dos widgets da tela inicial na horizontal, vertical
ou nos dois eixos. Os usuários tocam e pressionam um widget para mostrar as alças de redimensionamento e arrastam as alças horizontais ou verticais para mudar o tamanho na grade de layout. Os valores para o atributo resizeMode incluem
horizontal, vertical e none. Para
declarar um widget como redimensionável na horizontal e na vertical, 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 padrão do widget é 2x2. O widget pode ser redimensionado para baixo até 2x1 ou para cima 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 padrão do widget é 3x2. O widget pode ser redimensionado para 2x1 ou até tela cheia.
Outros atributos do widget
A tabela a seguir descreve os atributos <appwidget-provider> relacionados a qualidades que não sejam o dimensionamento de widgets.
| Atributos e descrição | |
|---|---|
updatePeriodMillis |
Define a frequência com que o framework de 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 conservar a 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 a seção Implementar uma atividade de configuração de widget nesta página. |
description |
Especifica a descrição que o seletor de widgets vai mostrar para seu 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çada 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. Para o Android 5.0 e versões posteriores, apenas home_screen é válido. |
widgetFeatures |
Declara os recursos compatíveis com o widget. Por exemplo, se a configuração do widget for opcional, especifique configuration_optional e reconfigurable. |
Definir GlanceAppWidget
Crie uma classe que estenda
GlanceAppWidgete substitua o métodoprovideGlance. Este é o método em que você pode carregar os dados necessários para renderizar seu 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
glanceAppWidgetno seuGlanceAppWidgetReceiver: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 AppWidgetProvider para processar transmissões de widgets
O widget de coordenadas GlanceAppWidgetReceiver transmite e atualiza o estado da plataforma
ao estender o AppWidgetProvider subjacente. Ele recebe eventos da plataforma quando o widget é atualizado, excluído, ativado ou desativado, traduzindo-os em solicitações do ciclo de vida do Compose.
Declarar um widget no manifesto
Declare a subclasse da classe GlanceAppWidgetReceiver como um broadcast receiver no
arquivo AndroidManifest.xml:
<receiver android:name="ExampleAppWidgetReceiver"
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 de receptor. O receptor precisa aceitar a ação de transmissão ACTION_APPWIDGET_UPDATE 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 AppWidgetProvider
No Glance, você estende GlanceAppWidgetReceiver em vez de
AppWidgetProvider diretamente. Implemente-o vinculando o receptor à sua instância do
GlanceAppWidget. Os callbacks principais disponíveis em
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 as linhas de execução de composição com êxito.onAppWidgetOptionsChanged(): chamado quando o widget é posicionado ou redimensionado pela primeira vez. As opções de leitura rápida agrupam itens nos bastidores para que seu layout se ajuste sem problemas com base nas dimensões de execução.onDeleted(Context, IntArray): invocado sempre que uma instância específica de widget é 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. Você precisa garantir que qualquer lógica de receptor personalizada que você escreva chamesuper.onReceive(context, intent)e nunca chamegoAsyncpor conta própria, já que o Glance encaminha o trabalho de forma assíncrona.
Receber intents de transmissão de widgets
Em segundo plano, o GlanceAppWidgetReceiver filtra e processa as seguintes
intenções de transmissão de widgets da plataforma fundamentais:
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
Columnaumenta o tamanho para corresponder ao espaço disponível (viaGlanceModifier) e alinha o conteúdo à parte de cima (verticalAlignment) e o centraliza horizontalmente (horizontalAlignment). - O conteúdo do
Columné definido usando a lambda. A ordem é importante.- O primeiro item no
Columné um componenteTextcom12.dpde padding. - O segundo item é um
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. Confira um exemplo de como ela pode aparecer:
- O primeiro item no
É possível mudar os valores de alinhamento ou aplicar valores de modificadores diferentes (como padding) para mudar o posicionamento e o tamanho dos componentes. Consulte a documentação de referência para ver 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 apps 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 corte do 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 do 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 substituições 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>