Já coloquei aqui no blog como criar um Widget, mas hoje vou mostrar como tratar eventos em componentes de um Widget.
Crie um novo projeto Android. Vamos começar criando o arquivo de layout do widget. Crie um arquivo /res/layout/widget.xml e deixe-o como abaixo. A imagem que eu estou usando como background eu peguei no próprio diretório do SDK. Procurem por *.9.png lá que vocês vão achar um monte :)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/widget_bg"
>
<Button
android:layout_width="wrap_content"
android:id="@+id/prev" android:text="<<"
android:layout_height="fill_parent"></Button>
<TextView
android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFF"
android:layout_weight="1"
android:gravity="center">
</TextView>
<Button
android:layout_width="wrap_content"
android:id="@+id/next"
android:text=">>"
android:layout_height="fill_parent">
</Button>
</LinearLayout>
Depois, vamos descrever o nosso Widget. Crie o arquivo /res/xml/meuwidget_info.xml. Nesse arquivo, descrevemos o tamanho do widget e o layout que o representa.
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dp"
android:minHeight="72dp"
android:initialLayout="@layout/widget"
>
</appwidget-provider>
Agora é só criarmos a classe que vai carregar o nosso Widget. Ela herda de AppWidgetProvider, que por sua vez herda de BroadcastReceiver. Logo a maioria do processo de atualização do widget é feito via mensagens de broadcast.
public class MeuWidgetProvider
extends AppWidgetProvider {
private static final String ACTION =
"ngvl.android.meuwidget.WIDGET_CONTROL";
private static final String LOG_TAG = "MeuWidget";
public static final String URI_SCHEME = "meuwidget";
private static int count;
@Override
public void onUpdate(Context context,
AppWidgetManager wm, int[] appWidgetIds) {
Log.d(LOG_TAG, "onUpdate(): ");
int id = appWidgetIds[0];
Log.d(LOG_TAG, "appWidgetId: "+ id);
RemoteViews remoteView = new RemoteViews(
context.getPackageName(), R.layout.widget);
remoteView.setTextViewText(
R.id.TextView01, "texto inicial");
atualizaViews(context, id, remoteView);
}
private void atualizaViews(Context context,
int widgetId, RemoteViews remoteView) {
remoteView.setOnClickPendingIntent(
R.id.next,
getPendingIntent(context, "next", widgetId));
remoteView.setOnClickPendingIntent(
R.id.prev,
getPendingIntent(context, "prev", widgetId));
AppWidgetManager.getInstance(context).
updateAppWidget(widgetId, remoteView);
}
private PendingIntent getPendingIntent(
Context context, String command, int appWidgetId){
Intent active = new Intent();
active.setAction(ACTION);
active.putExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
appWidgetId);
Uri data = Uri.withAppendedPath(
Uri.parse(URI_SCHEME+"://widget/id/#"+command),
String.valueOf(appWidgetId));
active.setData(data);
return PendingIntent.getBroadcast(
context, 0, active, PendingIntent.FLAG_ONE_SHOT);
}
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(LOG_TAG, "OnReceive:Action: " + action);
// Bug conhecido do Android 1.5
if (AppWidgetManager.ACTION_APPWIDGET_DELETED.
equals(action)) {
final int appWidgetId =
intent.getExtras().getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId !=
AppWidgetManager.INVALID_APPWIDGET_ID) {
this.onDeleted(context, new int[]{appWidgetId});
}
} else if (ACTION.equals(action)) {
final int appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId !=
AppWidgetManager.INVALID_APPWIDGET_ID) {
this.trataAcao(context, appWidgetId,
intent.getData());
}
} else {
super.onReceive(context, intent);
}
}
public void trataAcao(Context context,
int appWidgetId, Uri data) {
Log.d(LOG_TAG, "onHandleAction: "+ appWidgetId);
RemoteViews remoteView = new RemoteViews(
context.getPackageName(), R.layout.widget);
Log.d(LOG_TAG, "data = "+ data);
String controlType = data.getFragment();
if (controlType.equalsIgnoreCase("prev")) {
remoteView.setTextViewText(
R.id.TextView01, "Count: "+ --count);
} else if (controlType.equalsIgnoreCase("next")) {
remoteView.setTextViewText(
R.id.TextView01, "Count: "+ ++count);
}
atualizaViews(context, appWidgetId, remoteView);
}
}
O método onUpdate() é chamado quando adicionamos o widget na HomeScreen. Nele estamos obtendo as view remotas. A classe RemoteViews representa views que estão em outro processo, que nesse caso é a aplicação de Home onde ficam os widgets. Então nós obtemos apenas as nossas (baseado no pacote da aplicação e no arquivo de layout). Uma vez com as referencias das views, podemos definir o texto inicial e setar o evento de clique. Esse evento está sendo definido no método atualizaViews().
Os eventos de clique disparam PendingItents para o próprio widget (lembre-se que ele é uma subclasse de BroadcastReceiver). Esses eventos são tratados (como todo receiver) pelo método onReceive() que chama o método trataAcao() para atualizar o texto da view e "reassignar" os eventos aos botões.
Agora declare o widget no AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="ngvl.android.meuwidget"
android:versionCode="1"
android:versionName="1.0">
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:debuggable="true">
<receiver
android:name=".MeuWidgetProvider">
<intent-filter>
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action
android:name="ngvl.android.meuwidget.WIDGET_CONTROL" />
<data android:scheme="meuwidget" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/meuwidget_info" />
</receiver>
</application>
</manifest>
Notem que a declaração do Widget é com a tag receiver e no meta-data passamos o arquivo XML com suas configurações. Notem que temos dois intent-filters para o widget: um com a ação android.appwidget.action.APPWIDGET_UPDATE que deve sempre ser declarado, e outro com a ação qeu disparamos no clique do botão.
A estrutura final do projeto ficará dessa forma:
Execute a aplicação, dê um clique longo na HomeScreen e adicione o widget à tela. O resultado é exibido na figura abaixo :)
Estou sem tempo de explicar bem o exemplo, mas tentem colocar pra rodar e qualquer dúvida, postem comentários aqui :)
4br4ç05,
nglauber
Nenhum comentário:
Postar um comentário