如何将 onClick 侦听器附加到应用小部件上的列表视图项

how to attach a onClick Listener to a listview item on an app widget

我想为我的列表视图的每个项目添加一个 onClick 监听器,但我尝试过的方法都不起作用。

这是我的 RemoteViewsFactory:

public class MyRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {

    [...]

    public RemoteViews getViewAt(int position) {

        final RemoteViews remoteView = new RemoteViews(
            context.getPackageName(), R.layout.widget_item);

        [...]

        final Intent activityIntent = new Intent(context, ListActivity.class);
        activityIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        activityIntent.putExtra(AppWidgetManager.ACTION_APPWIDGET_PICK, position);
        PendingIntent pI = PendingIntent.getActivity(
            context, appWidgetId, activityIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        remoteView.setOnClickPendingIntent(R.id.item_frame, pI);

        return remoteView;
    }
}

列表-widget.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget_frame"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical" >

    <include layout="@layout/picture_frame" />

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_toRightOf="@+id/picframe"
        android:layout_margin="5dp"
        android:gravity="center"
        android:loopViews="true" />

</RelativeLayout>

列表-item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_frame"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center_horizontal"
    android:layout_centerVertical="true" >

    <TextView
        android:id="@+id/date"
        style="@style/WidgetItemText" />

    <TextView
        android:id="@+id/name"
        style="@style/WidgetItemText" />

</LinearLayout>

如果我点击一个项目,什么也没有发生。

如果我将其直接挂在列表视图的提供程序中,则 Intent 工作正常,但我无法再滚动并且无法响应单个项目。

您可以尝试类似的操作,其中 position 是您的项目在列表视图中的索引

ListView lv = getListView();
setContentView(lv);
lv.setOnItemClickListener(new OnItemClickListener()
{
@Override 
public void onItemClick(AdapterView<?> arg0, View arg1,int position, long arg3)
{ 
    Toast.makeText(SuggestionActivity.this, "" + position, Toast.LENGTH_SHORT).show();
}
});

Adding behavior to individual itemsofficial doc 中的部分说:

As described in Using the AppWidgetProvider Class, you normally use setOnClickPendingIntent() to set an object's click behavior—such as to cause a button to launch an Activity. But this approach is not allowed for child views in an individual collection item (to clarify, you could use setOnClickPendingIntent() to set up a global button in the Gmail app widget that launches the app, for example, but not on the individual list items). Instead, to add click behavior to individual items in a collection, you use setOnClickFillInIntent(). This entails setting up up a pending intent template for your collection view, and then setting a fill-in intent on each item in the collection via your RemoteViewsFactory.

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. The fill-in intent is then combined with the PendingIntent template in order to determine the final intent that will be executed when the item is clicked.

您需要调用 setOnClickFillInIntent 来区分项目 on-click 行为。像这样:

public RemoteViews getViewAt(int position) {

        final RemoteViews remoteView = new RemoteViews(
            context.getPackageName(), R.layout.widget_item);

        [...]

        // Next, set a fill-intent, which will be used to fill in the pending intent template
        // that is set on the collection view in StackWidgetProvider.
        Bundle extras = new Bundle();
        extras.putInt(YouWidgetProvider.EXTRA_ITEM, position);
        Intent fillInIntent = new Intent();
        fillInIntent.putExtras(extras);
        // Make it possible to distinguish the individual on-click
        // action of a given item
        remoteView.setOnClickFillInIntent(R.id.item_frame, fillInIntent);


        return remoteView;
    }

还应该使用 setPendingIntentTemplate 而不是 setOnClickPendingIntent 来在集合上设置单个 PendingIntent 模板。在对应于 AppWidgetProvider 子类的 onUpdate 方法中设置未决意图,如下所示:

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // update each of the app widgets with the remote adapter
        for (int i = 0; i < appWidgetIds.length; ++i) {
            ...
            RemoteViews remoteView = new RemoteViews(context.getPackageName(), 
                R.layout.widget_item);
            ...

            // This section makes it possible for items to have individualized behavior.
            // It does this by setting up a pending intent template. Individuals items of a collection
            // cannot set up their own pending intents. Instead, the collection as a whole sets
            // up a pending intent template, and the individual items set a fillInIntent
            // to create unique behavior on an item-by-item basis.
            Intent activityIntent = new Intent(context, ListActivity.class);
            // Set the action for the intent.
            // When the user touches a particular view.
            activityIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
            activityIntent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
            PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], 
                activityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setPendingIntentTemplate(R.id.stack_view, pendingIntent);

            appWidgetManager.updateAppWidget(appWidgetIds[i], remoteView);
        }
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }

With this Code you can add onClick for every ListView item in Widget and can pass data from widget item to start new Activity with this data.

在小部件中,您无法为列表或堆栈中的每个项目创建一个单独的 Intent。为此,我们必须为我们创建的每个列表项创建 Intent,并在 WidgetService 中包含数据。

这是WidgetService.java。我用我想发送的额外数据创建了一个 new Intent。 然后我选择哪个 UI 元素将成为此函数中的触发器 views.setOnClickFillInIntent

  @Override
    public RemoteViews getViewAt(int position) {
        final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_item);

        //Open Post
        Intent fillIntent = new Intent();
        fillIntent.putExtra(
                "keyData", position);
        views.setOnClickFillInIntent(R.id.tvTitle, fillIntent);

    .....
   }

这是ExampleWidgetProvider.java

public static final String ACTION_POST = "actionPost";

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    // update each of the app widgets with the remote adapter
    for (int i = 0; i < appWidgetIds.length; ++i) {
        ...
        RemoteViews remoteView = new RemoteViews(context.getPackageName(), 
            R.layout.listview);


        ...


        Intent postIntent = new Intent(context, ExampleWidgetProvider.class);
        postIntent.setAction(ACTION_POST);
        PendingIntent postPendingIntent = PendingIntent.getBroadcast(context,
                0, postIntent, 0);


        ...


            activityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setPendingIntentTemplate(R.id.listview, postPendingIntent );

        appWidgetManager.updateAppWidget(appWidgetIds[i], remoteView);
    }
    super.onUpdate(context, appWidgetManager, appWidgetIds);
}

我们已经为每个 ListView 项目创建了 OnClick,它将向自身发送意图给这个 ExampleWidgetProvider.java。现在我们必须读取 IntentWidgetService.java 中为每个列表项发送的信息。

为此,我们必须在 ExampleWidgetProvider.java.

中创建另一个函数
@Override
    public void onReceive(Context context, Intent intent) {
        if(ACTION_POST.equals(intent.getAction())){

            //Passed info from WidgetService.java
            String data= intent.getStringExtra("keyData");

            // If you want to open new activity with this data you can do it
            Intent intentPOST = new Intent(context,
                    MainActivity.class).putExtra(
                    "keyData", data);
            intentPOST.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity (intentPOST);


            //Show information
            Toast.makeText(context,
                    data,
                   Toast.LENGTH_LONG).show();
        }
        super.onReceive(context, intent);
    }