Search code examples
androidandroid-widgetviewflipper

Setting click listeners on individual elements in a ViewFlipper widget


I am building a collection Widget backed by a ViewFlipper, and ran into a snag when following the Android docs on adding behavior to individual items.

I want to create two arrows which move the ViewFlipper to its previous and next views, as shown in this mockup:

enter image description here

In my WidgetService's getViewAt() method, I have the following code to create a fill in intent:

final Intent fillInIntent = new Intent();
final Bundle bundle = new Bundle();
bundle.putInt(WidgetProvider.EXTRA_ID, mWidgetItems.get(position));
fillInIntent.putExtras(bundle);
remoteViews.setOnClickFillInIntent(R.id.btn_widget_next, fillInIntent);
remoteViews.setOnClickFillInIntent(R.id.btn_widget_previous, fillInIntent);

And then in my WidgetProvider I have this:

// Adding collection list item handler
final Intent onItemClick = new Intent(context, WidgetProvider.class);
onItemClick.setAction(NAVIGATE);
onItemClick.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id)
onItemClick.setData(Uri.parse(onItemClick.toUri(Intent.URI_INTENT_SCHEME)));
final PendingIntent onClickPendingIntent = PendingIntent
  .getBroadcast(context, id, onItemClick,
     PendingIntent.FLAG_UPDATE_CURRENT);
rv.setPendingIntentTemplate(R.id.widget_view_flipper, onClickPendingIntent);

What confuses me about the design here is whether or not I am supposed to be calling setOnClickFillInIntent on each button. If I do set the intent on each button, I need a way of determining which button was clicked in my WidgetProvider's onUpdate method (all I have now is the position of the view in the ViewFlipper). I wasn't able to find an example of a Widget that uses click listeners for more than one action unfortunately.


Solution

  • The documentation you linked to is a bit misleading with the following sentence:

    Your RemoteViewsFactory must set a fill-in intent on each item in the collection.This makes it possible to distinguish the individual on-click action of a given item

    Well, you never really know until you try: it is possible after all to set fill-in-intents on individual children of the RemoteViews item. But you have to use a separate Intent for each of the buttons. I'll show how for the NEXT-button:

    final Intent fillInIntent = new Intent();
    final Bundle bundle = new Bundle();
    bundle.putInt(WidgetProvider.EXTRA_ID, mWidgetItems.get(position));
    bundle.putBoolean("FLIP_TO_NEXT", true);
    fillInIntent.putExtras(bundle);
    remoteViews.setOnClickFillInIntent(R.id.btn_widget_next, fillInIntent);
    

    Then you have to check the Intent action (NAVIGATE) as well as the value of intent.getBooleanExtra("FLIP_TO_NEXT", false) in onReceive() and update the app widget accordingly. For example if "NEXT" was clicked:

    ComponentName me = new ComponentName(this, ViewFlipperWidget.class);
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); 
    int appWidgetID = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
    if (appWidgetID != AppWidgetManager.INVALID_APPWIDGET_ID)
    {
         RemoteViews rv = new RemoteViews(getPackageName(), R.layout.view_flipper_widget);
         if (intent.getBooleanExtra("FLIP_TO_NEXT", false))
         {
              rv.showNext(R.id.viewFlipper);
         }
         else 
         {
              rv.showPrevious(R.id.viewFlipper);
         }
         appWidgetManager.updateAppWidget(appWidgetID, rv);
    }