使用ListView项内的按钮触发PopupMenu

ata*_*ulm 14 android listview android-contextmenu

菜单类型

首先让我概述一下Contextual Menus和Popup Menus之间的区别(取自这里):

  • PopupMenu是一个锚定到View 的模式菜单

  • 上下文菜单[我特别谈论浮动上下文菜单]提供了影响UI中特定项目或上下文框架的操作.您可以为任何视图提供上下文菜单,但它们通常用于ListView,GridView或其他视图集合中的项目,用户可以在其中对每个项目执行直接操作.

作为指导,文档区分了它们的用途: - PopupMenu:"为特定内容相关的操作提供溢出式菜单(例如Gmail的电子邮件标题......" - ContextualMenu:"对于影响所选内容的操作... "

我正在追寻PopupMenu的视觉外观和互动.

我的设置(和目标)

我有一个ListView,其中每个项目右侧都有一个按钮.

--------------------
| Item 1        [ ]|
--------------------
--------------------
| Item ...      [ ]|
--------------------
--------------------
| Item n        [ ]|
--------------------
Run Code Online (Sandbox Code Playgroud)

同时保留onItemClick每个ListItem,我想利用按钮触发一个PopupMenu.

其中的操作PopupMenu列在my_menu.xml,因此菜单的每个实例之间的唯一区别是它被单击的项目.

我试过的

根据这篇文章,我已经尝试覆盖getView()ListAdapterOnClickListener每个按钮添加一个按钮.结果不一致; 并非所有的点击都在注册(可能是由于回收 - 我还没有尝试过这个修复)但总的来说这种方法看起来很麻烦,考虑到为列表视图指定上下文菜单的简易性.

我还尝试添加一个上下文菜单,这很简单,只有当列表项被长按时才触发.

getView()方法是可行的方法还是更简单的方法?

在我的列表视图中,我为每个项目设置了一个迷你溢出按钮,类似于播放音乐的播放列表中的每个曲目.当您单击溢出按钮时,它们会为每个项目显示PopupMenu.长按什么都不做.

我想那样但不确定怎么样?菜单页面仅详细说明了如何为各个视图启用弹出菜单.

registerForContextMenu(ListView lv)是我见过的唯一可以应用于整个ListView的东西,但这似乎只适用于整个列表的长按.有没有办法将该事件挂钩到单击列表项中的特定视图(同时仍然保持列表项单击列表项的其余部分)?

我已经尝试过如此描述的设置onClickListener,getView()但是对于PopupMenu来说感觉很糟糕,而且并不是所有的点击都是每次注册(它始终不一致).

更新 - 再次覆盖getView()

当我创建StacksCursorAdapter时,我传递一个StackViewFragment实例,它存储为一个字段(因此它可以作为点击监听器分配给视图).

ViewHolder 是一个班级 public final ImageView miniOverflow

StacksCursorAdapter(扩展SimpleCursorAdapter):

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row = super.getView(position, convertView, parent);
    ViewHolder holder = (ViewHolder) row.getTag();

    if (holder == null) {
        holder = new ViewHolder(row);
        row.setTag(holder);
    }
    holder.miniOverflow.setTag(R.id.tag_stack_position, position);
    holder.miniOverflow.setOnClickListener(listener);

    return row;
}
Run Code Online (Sandbox Code Playgroud)

StackViewFragment(扩展ListFragment,实现View.OnClickListener):

@Override
public void onClick(View v) {
    Log.d(TAG, "mini overflow clicked");
    Log.d(TAG, "position:::::" + v.getTag(R.id.tag_stack_position));

    PopupMenu popup = new PopupMenu(getActivity(), v);
    MenuInflater inflater = popup.getMenuInflater();
    inflater.inflate(R.menu.menu_stackview_listitem, popup.getMenu());
    popup.show();
}
Run Code Online (Sandbox Code Playgroud)

stack_list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- a single row item for a Stacks listview -->
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:descendantFocusability="blocksDescendants"
        >

    ...
    <other views>
    ...


    <ImageView
            android:id="@+id/moreoverflow_btn"
            android:focusable="false"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:alpha="0.4"
            android:scaleType="fitCenter"
            android:src="@drawable/ic_menu_moreoverflow_black"
            android:layout_alignParentRight="true"
            />
</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

这个交叉点的问题是我必须偶尔点击几次以点击注册(在按钮上).这是没有滚动,所以它与视图回收无关.

结论(eskimoapps.com解决方案标记为正确)

因此,除了我的触摸目标不在我期望的位置之外,多次点击没有问题 - 我用于迷你溢出的图像资源被加权到右边(这样三个点靠近右边缘触摸目标)意味着我只是错过了一半的时间(facepalm).

getView()如上所示,覆盖似乎工作正常,事实上,getView()只有在需要时才设置OnClickListener ,可以进一步修改(但绝对需要为每个视图更新标记,而不仅仅是新创建的标记) :

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row = super.getView(position, convertView, parent);
    ViewHolder holder = (ViewHolder) row.getTag();

    if (holder == null) {
        holder = new ViewHolder(row);
        row.setTag(holder);
        holder.miniOverflow.setOnClickListener(listener);
    }
    holder.miniOverflow.setTag(R.id.tag_stack_position, position);

    return row;
}
Run Code Online (Sandbox Code Playgroud)

esk*_*ski 3

重写 getView 是正确的方法,并且您认为回收视图会使事情变得复杂(如果您实际上正在回收视图),那么您的想法是正确的。

由于没有 getOnClickListener 方法,您只需为回收的视图以及未膨胀的视图设置一个新的 OnClickListener(如果您不想创建实现 getOnClickListener 的自定义视图)。