Os widgets de aplicativos são visualizações de aplicativos em miniatura que podem ser incorporadas a outros (como a tela inicial) e receber atualizações periódicas. Esses são chamadas de widgets na interface do usuário, e você pode publicar uma com um provedor de widgets de apps (ou provedor de widgets). Um componente do app que contém outros widgets é chamado de host de widget de app (ou host de widget). Figura 1 mostra um exemplo de widget de música:
Neste documento, descrevemos como publicar um widget usando um provedor. Para
detalhes sobre como criar seu próprio AppWidgetHost
para
widgets de apps hospedados, consulte Criar um host de widgets.
Para saber mais sobre como projetar seu widget, consulte Visão geral dos widgets de apps.
Componentes do widget
Para criar um widget, você precisa dos seguintes componentes básicos:
- Objeto
AppWidgetProviderInfo
- Descreve os metadados de um widget, como o layout, atualização
frequência e classe
AppWidgetProvider
.AppWidgetProviderInfo
é definido em XML, conforme descritas neste documento. - Classe
AppWidgetProvider
- Define os métodos básicos que permitem interagir programaticamente com o
widget. Com ele, você recebe transmissões quando o widget é atualizado
ativado, desativado ou excluído. Você declara
AppWidgetProvider
no manifesto do app e implementá-lo como descritas neste documento. - Layout de visualização
- Define o layout inicial do widget. O layout é definido em XML, conforme descrito neste documento.
A Figura 2 mostra como esses componentes se encaixam no processamento geral de widgets de apps. fluxo
.Se o widget precisar de configuração do usuário, implemente a configuração do widget de app atividades. Essa atividade permite que os usuários modifiquem as configurações do widget, por exemplo, fuso horário para um widget de relógio.
- A partir do Android 12 (nível 31 da API), é possível fornecer uma e permitir que os usuários reconfigurem o widget mais tarde. Consulte Usar o a configuração padrão do widget e Ativar os usuários reconfigurarem widgets posicionados para mais detalhes.
- No Android 11 (nível 30 da API) ou versões anteriores, essa atividade é iniciada sempre que o usuário adiciona o widget à tela inicial.
Também recomendamos as seguintes melhorias: layouts flexíveis de widgets, melhorias diversas, widgets avançados, widgets de coleção e a criação de um widget. host.
Declarar o XML do AppWidgetProviderInfo
O objeto AppWidgetProviderInfo
define as qualidades essenciais de um widget.
Defina o objeto AppWidgetProviderInfo
em um arquivo de recurso XML usando uma única
<appwidget-provider>
e salve-o na pasta res/xml/
do projeto.
Isso é mostrado neste exemplo:
<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/example_loading_appwidget"
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 horizontalmente por três células na vertical.
Os atributos de dimensionamento do widget permitem especificar um tamanho padrão para ele e fornecem limites inferior e superior para o tamanho do widget. Nesse contexto, a o tamanho padrão de um widget é o tamanho que ele assume quando é pela primeira vez foi adicionado à tela inicial.
A tabela a seguir descreve os atributos <appwidget-provider>
relacionados
até o dimensionamento de widgets:
Atributos e descrição | |
---|---|
targetCellWidth e
targetCellHeight (Android 12)
minWidth e minHeight |
targetCellWidth e
targetCellHeight , minWidth e
minHeight para que seu app possa voltar a usar
minWidth e minHeight se o dispositivo do usuário
não oferece suporte a targetCellWidth e
targetCellHeight Se compatível, o
Atributos targetCellWidth e targetCellHeight
têm precedência sobre minWidth e minHeight
atributos.
|
minResizeWidth e
minResizeHeight |
Especifique o tamanho mínimo absoluto do widget. Esses valores especificam
tamanho em que o widget fica ilegível ou inutilizável. Usando
esses atributos permitem que o usuário redimensione o widget para um tamanho menor
que o tamanho de widget padrão. O atributo minResizeWidth é
ignorado se for maior que minWidth ou se for horizontal
o redimensionamento não está ativado. Consulte
resizeMode Da mesma forma,
O atributo minResizeHeight será 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
um múltiplo das dimensões da célula da grade, elas são arredondadas para cima
tamanho da célula. O atributo maxResizeWidth será ignorado se for
menor que minWidth ou se o redimensionamento horizontal não for
ativado. Consulte resizeMode . Da mesma forma,
o atributo maxResizeHeight será ignorado se for maior
do 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 isso
para tornar os widgets da tela inicial redimensionáveis horizontalmente, verticalmente
ou nos dois eixos. Os usuários tocam e segurar um widget para mostrar as alças de redimensionamento
depois arraste as alças horizontais ou verticais para alterar o tamanho na
grade de 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, assumem as seguintes especificações:
- Uma célula de 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 padrão
tamanho do widget.
O tamanho do widget é 2x2 por padrão. O widget pode ser redimensionado para 2 x 1 ou até 4 x 3.
Android 11 e versões anteriores:
Use os atributos minWidth
e minHeight
para calcular o tamanho padrão do
no 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 2 x 1 ou para a tela cheia.
Outros atributos do widget
A tabela a seguir descreve os atributos <appwidget-provider>
relacionados
qualidades diferentes do dimensionamento de widgets.
Atributos e descrição | |
---|---|
updatePeriodMillis |
Define com que frequência o framework do widget solicita uma atualização do
AppWidgetProvider chamando o método onUpdate()
método de callback. Não há garantia de que a atualização ocorrerá exatamente no dia
com esse valor, e recomendamos que a atualização seja feita com pouca frequência
possível (não mais do que uma vez por hora) para conservar a bateria.
Para acessar a lista completa de considerações para escolher um período de atualização apropriado,
ver
Otimizações para atualizar o widget
. |
initialLayout |
Aponta para o recurso de layout que define o layout do widget. |
configure |
Define a atividade iniciada quando o usuário adiciona o widget permitindo que configurem as propriedades do widget. Consulte Permita que os usuários configurem widgets. A partir do Android 12, o app pode pular a fase inicial configuração do Terraform. Consulte Usar o a configuração padrão do widget para mais detalhes. |
description |
Especifica a descrição a ser exibida pelo seletor de widgets para seu widget. Introduzido no Android 12. |
previewLayout (Android 12)
e previewImage (Android 11 e versões anteriores) |
previewImage
e previewLayout para que seu app possa usar
a usar previewImage se o dispositivo do usuário não for compatível
previewLayout . Para mais detalhes, consulte
Compatibilidade com versões anteriores
visualizações de widgets.
|
autoAdvanceViewId |
Especifica o ID da visualização da subvisualização do widget que é avançada automaticamente pelo host do widget. |
widgetCategory |
Declara se o widget pode ser exibido na tela inicial
(home_screen ), a tela de bloqueio (keyguard ) ou
os dois. Para o Android 5.0 e versões mais recentes, apenas home_screen é válido.
|
widgetFeatures |
Declara os recursos com suporte do widget. Por exemplo, se quiser
seu widget para usar a configuração padrão quando um usuário o adicionar, especifique
os dois
configuration_optional
e
reconfigurable
de status. Isso ignora a inicialização da atividade de configuração depois que um usuário
adiciona o widget. O usuário ainda pode
reconfigurar o widget
depois. |
Usar a classe AppWidgetProvider para processar transmissões de widgets
A classe AppWidgetProvider
processa as transmissões do widget e atualiza o widget.
em resposta a eventos de ciclo de vida do widget. As seções a seguir descrevem como
Declare AppWidgetProvider
no manifesto e o implemente.
Declarar um widget no manifesto
Primeiro, declare a classe AppWidgetProvider
no AndroidManifest.xml
do app
conforme mostrado no exemplo a seguir:
<receiver android:name="ExampleAppWidgetProvider"
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/example_appwidget_info" />
</receiver>
O elemento <receiver>
requer o atributo android:name
, que especifica
AppWidgetProvider
usado pelo widget. O componente não pode ser exportado
a menos que um processo separado precise transmitir para sua AppWidgetProvider
, que
geralmente não é o caso.
O elemento <intent-filter>
precisa incluir um elemento <action>
com o
android:name
. Esse atributo especifica que o AppWidgetProvider
aceita o
ACTION_APPWIDGET_UPDATE
transmissão. Essa é a única transmissão que precisa ser declarada explicitamente. A
AppWidgetManager
automaticamente envia todas as outras transmissões de widget para o AppWidgetProvider
conforme
necessários.
O elemento <meta-data>
especifica o recurso AppWidgetProviderInfo
e
requer os seguintes atributos:
android:name
: especifica o nome dos metadados. Usarandroid.appwidget.provider
para identificar os dados DescritorAppWidgetProviderInfo
.android:resource
: especifica o recursoAppWidgetProviderInfo
. o local.
Implementar a classe AppWidgetProvider
A classe AppWidgetProvider
estende
BroadcastReceiver
como um
de conveniência para lidar com transmissões de widget. Ele recebe apenas o evento
transmissões relevantes para o widget, como quando ele é atualizado,
excluídas, ativadas e desativadas. Quando esses eventos de transmissão ocorrem,
Os métodos AppWidgetProvider
são chamados:
onUpdate()
- É chamado para atualizar o widget nos intervalos definidos pelo
updatePeriodMillis
noAppWidgetProviderInfo
. Consulte a tabela descrevendo atributos adicionais de widget nesta página para mais informações. .
- Esse método também é chamado quando o usuário adiciona o widget. Ele executa a
configuração essencial, como definir manipuladores de eventos para
Objetos
View
ou iniciando jobs para carregar dados em exibir no widget. No entanto, se você declarar uma atividade de configuração sem a sinalizaçãoconfiguration_optional
, esse método não é chamado quando o usuário adiciona o widget, mas é chamado para as atualizações subsequentes. É o responsabilidade da atividade de configuração realizar a primeira atualização ao quando a configuração é concluída. Consulte Permitir que os usuários configurem widgets de apps para mais informações. .
- O callback mais importante é
onUpdate()
. Consulte Processar eventos com oonUpdate()
nesta página para mais informações. onAppWidgetOptionsChanged()
É chamado quando o widget é colocado pela primeira vez e sempre que o widget é redimensionados. Use este callback para mostrar ou ocultar conteúdo com base no tamanho do widget intervalos. Confira os intervalos de tamanho e, a partir do Android 12, a lista de tamanhos possíveis que uma instância de widget pode assumir, chamando
getAppWidgetOptions()
, que retorna umBundle
que inclui o seguinte:OPTION_APPWIDGET_MIN_WIDTH
: contém o limite inferior da largura, em unidades dp, de uma instância de widget.OPTION_APPWIDGET_MIN_HEIGHT
: contém o limite inferior da altura, em unidades dp, de uma instância de widget.OPTION_APPWIDGET_MAX_WIDTH
: contém o limite superior da largura, em unidades dp, de uma instância de widget.OPTION_APPWIDGET_MAX_HEIGHT
: contém o limite superior da altura, em unidades dp, de uma instância de widget.OPTION_APPWIDGET_SIZES
: contém a lista de tamanhos possíveis (List<SizeF>
), em unidades dp, que um que a instância de widget pode tomar. Introduzido no Android 12.
onDeleted(Context, int[])
É chamado sempre que um widget é excluído do host.
onEnabled(Context)
Ele é chamado quando uma instância do widget é criada pela primeira vez. Por exemplo, se o usuário adicionar duas instâncias do seu widget, isso será chamado apenas pela primeira vez. Se você precisar abrir um novo banco de dados ou executar outra configuração que só precisa ocorrer uma vez para todas as instâncias de widget, então esse é um bom lugar para fazer isso.
onDisabled(Context)
Ele é chamado quando a última instância do widget é excluída da host do widget. É aqui que você limpa todo o trabalho feito em
onEnabled(Context)
, como excluir um banco de dados temporário.onReceive(Context, Intent)
É chamado para cada transmissão e antes de cada callback anterior métodos. Normalmente, não é necessário implementar esse método, porque o padrão A implementação de
AppWidgetProvider
filtra todas as transmissões do widget e chama o métodos anteriores conforme apropriado.
É necessário declarar a implementação da classe AppWidgetProvider
como uma transmissão
receptor usando o elemento <receiver>
no AndroidManifest
. Consulte Declarar um
no manifesto desta página para mais informações.
Processar eventos com a classe onUpdate()
O callback AppWidgetProvider
mais importante é onUpdate()
, porque é
chamado quando cada widget é adicionado a um host, a menos que você use uma configuração
sem a flag configuration_optional
. Se o widget aceitar qualquer
eventos de interação do usuário e, em seguida, registre os manipuladores de eventos nesse retorno de chamada. Se
o widget não cria arquivos temporários ou bancos de dados nem realiza outro trabalho
que exigir limpeza, onUpdate()
poderá ser o único método de callback que você
que precisamos definir.
Por exemplo, se você quiser um widget com um botão que inicie uma atividade quando
tocado, você pode usar a seguinte implementação de AppWidgetProvider
:
Kotlin
class ExampleAppWidgetProvider : AppWidgetProvider() { override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { // Perform this loop procedure for each widget that belongs to this // provider. appWidgetIds.forEach { appWidgetId -> // Create an Intent to launch ExampleActivity. val pendingIntent: PendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ Intent(context, ExampleActivity::class.java), /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // Get the layout for the widget and attach an onClick listener to // the button. val views: RemoteViews = RemoteViews( context.packageName, R.layout.appwidget_provider_layout ).apply { setOnClickPendingIntent(R.id.button, pendingIntent) } // Tell the AppWidgetManager to perform an update on the current // widget. appWidgetManager.updateAppWidget(appWidgetId, views) } } }
Java
public class ExampleAppWidgetProvider extends AppWidgetProvider { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Perform this loop procedure for each widget that belongs to this // provider. for (int i=0; i < appWidgetIds.length; i++) { int appWidgetId = appWidgetIds[i]; // Create an Intent to launch ExampleActivity Intent intent = new Intent(context, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ intent, /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); // Get the layout for the widget and attach an onClick listener to // the button. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout); views.setOnClickPendingIntent(R.id.button, pendingIntent); // Tell the AppWidgetManager to perform an update on the current app // widget. appWidgetManager.updateAppWidget(appWidgetId, views); } } }
Esse AppWidgetProvider
define apenas o método onUpdate()
, usando-o para
criar um PendingIntent
que inicie
um Activity
e o anexa ao widget
botão usando setOnClickPendingIntent(int,
PendingIntent)
. Ele inclui um loop que itera em cada entrada
em appWidgetIds
, que é uma matriz de IDs que identificam cada widget criado pelo
esse provedor. Se o usuário criar mais de uma instância do widget,
elas serão atualizadas simultaneamente. No entanto, apenas uma programação updatePeriodMillis
é gerenciado para todas as instâncias do widget. Por exemplo, se o cronograma de atualização
a cada duas horas, e uma segunda instância do widget é adicionada
uma hora após o primeiro, ambos são atualizados no período definido pelo
o primeiro, e o segundo é ignorado. Ambos são atualizados a cada dois
horas, não a cada hora.
Consulte a
ExampleAppWidgetProvider.java
para mais detalhes.
Receber intents de transmissão de widget
AppWidgetProvider
é uma classe de conveniência. Se você quiser receber o widget
transmissões diretamente, é possível implementar sua própria BroadcastReceiver
ou modificar
as
Callback onReceive(Context,Intent)
. As intents com as quais você precisa se preocupar são
seguinte:
ACTION_APPWIDGET_UPDATE
ACTION_APPWIDGET_DELETED
ACTION_APPWIDGET_ENABLED
ACTION_APPWIDGET_DISABLED
ACTION_APPWIDGET_OPTIONS_CHANGED
Criar o layout do widget
Você deve definir um layout inicial para seu widget em XML e salvá-lo no
diretório res/layout/
do projeto. Consulte Design
diretrizes para mais detalhes.
Criar o layout de widget é simples se você souber usar
layouts. No entanto, saiba que o widget
os layouts são baseados em RemoteViews
,
que não oferece suporte a todos os tipos de widget de layout ou visualização. Não é possível usar
Visualizações ou subclasses das visualizações com suporte a RemoteViews
.
RemoteViews
também oferece suporte a ViewStub
,
que é um View
invisível e de tamanho zero que pode ser usado para inflar lentamente o layout
recursos no ambiente de execução.
Suporte para comportamento com estado
O Android 12 adiciona suporte a comportamentos com estado usando o seguinte: componentes existentes:
O widget ainda não tem estado. O app precisa armazenar o estado e se registrar para eventos de mudança de estado.
.O exemplo de código a seguir mostra como implementar esses componentes.
Kotlin
// Check the view. remoteView.setCompoundButtonChecked(R.id.my_checkbox, true) // Check a radio group. remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2) // Listen for check changes. The intent has an extra with the key // EXTRA_CHECKED that specifies the current checked state of the view. remoteView.setOnCheckedChangeResponse( R.id.my_checkbox, RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent) )
Java
// Check the view. remoteView.setCompoundButtonChecked(R.id.my_checkbox, true); // Check a radio group. remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2); // Listen for check changes. The intent has an extra with the key // EXTRA_CHECKED that specifies the current checked state of the view. remoteView.setOnCheckedChangeResponse( R.id.my_checkbox, RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent));
Forneça dois layouts: um destinado a dispositivos com o Android 12 ou
mais alto em res/layout-v31
, e a outra segmentação anterior
Android 11 ou anterior na pasta res/layout
padrão.
Implementar cantos arredondados
O Android 12 apresenta os parâmetros do sistema abaixo para definir a raios dos cantos arredondados do widget:
system_app_widget_background_radius
: o raio do canto do plano de fundo do widget, que nunca é maior que 28 dp.system_app_widget_inner_radius
: o raio do canto de qualquer visualização dentro do widget. É exatamente 8 dp menor que o raio do plano de fundo, para se alinhar bem ao usar um raio de 8 dp padding.
O exemplo a seguir mostra um widget que usa
system_app_widget_background_radius
para o canto e
system_app_widget_inner_radius
para as visualizações dentro do widget.
1 Canto do widget.
2 Canto de uma visualização dentro do widget.
Considerações importantes sobre cantos arredondados
- Os inicializadores de terceiros e os fabricantes de dispositivos podem substituir o
o parâmetro
system_app_widget_background_radius
seja menor que 28 dp. O parâmetrosystem_app_widget_inner_radius
é sempre 8 dp menor que o valor desystem_app_widget_background_radius
. - Se o widget não usar
@android:id/background
ou definir um segundo plano que recorta o conteúdo com base no esboço, comandroid:clipToOutline
definido comotrue
: a tela de início identifica automaticamente o plano de fundo e recorta o widget usando um retângulo com cantos arredondados de até 16 dp. Consulte Verificar se o widget é compatível com Android 12
Para compatibilidade de widgets com versões anteriores do Android, recomendamos definir atributos personalizados e usar um tema personalizado para substituí-los para Android 12, conforme mostrado nos exemplos de arquivos XML abaixo:
/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>
/layout/my_widget_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
...
android:background="@drawable/my_widget_background" />