Android - 在RecyclerView的条目上长按并显示上下文菜单

8
问题:在RecyclerView中长按某一项时,无法显示包含"删除"选项的上下文菜单。
期望结果:请参见下方图片。
我已经接近成功,但是还需要添加一些东西才能使上下文菜单在长按时显示出来。
以下是我在ViewHolder中加入的代码。我不知道应该在onLongClick事件中添加什么以及如何显示上下文菜单。
我省略了一些代码行,只保留了与问题相关的代码。
非常感谢您的帮助,
我的接口处理两种类型的点击。
public interface OnItemClickListener{
    void onItemClick(int position);
}

public interface OnItemLongClickListener{
    void onItemLongClick(int position);
}

ViewHolder 代码

public void bindLongClick(final int position, final OnItemLongClickListener onItemLongClickListener) {
        itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                onItemLongClickListener.onItemLongClick(position);
                return true;
            }
        });
    }

    @Override
    public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo){
            //menuInfo is null
        Log.v(LOG_TAG, "grrr");
        contextMenu.setHeaderTitle("Select The Action");
        contextMenu.add(0, view.getId(), 0, "Supprimer");//groupId, itemId, order, title
    }

适配器代码

@Override
    public void onBindViewHolder(CityListViewholder holder, int position) {
        holder.cityName.setText(cityArrayList.get(position).getCityName());
        holder.bindClick(position, onItemClickListener);
        holder.bindLongClick(position, onItemLongClickListener);
    }

然后,在这个活动中——我跳过了与我的问题无关的部分。
mCityListAdapter = new CityListAdapter(mContext, cityArrayList, new CityListAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int position) {
                mPager.setCurrentItem(position);
                mDrawerLayout.closeDrawers();
            }
        }, new CityListAdapter.OnItemLongClickListener() {
            @Override
            public void onItemLongClick(int position) {
                Log.v(LOG_TAG, "Position "+position);
            }
        });

        registerForContextMenu(mRecyclerView);

Expected result


抱歉,似乎我没有完全理解?您是想在长按项目时显示弹出窗口吗? - Michael Spitsin
谢谢Michael,我更新了我的问题,并添加了一个期望的示例,以及在问题顶部更好的描述我的问题。 - Isabelle
@millinet 长按显示上下文菜单。根据您的代码,您没有实现任何长按功能。 - Jagjit Singh
@JagjitSingh 我知道,这就是我所缺少的。它可能很容易,但我无法弄清如何“调用/显示”它。 - Isabelle
你可以在StackOverflow文档中找到答案,链接如下:http://stackoverflow.com/documentation/android/169/recyclerview#t=201607270859508946896。使用RecyclerView查找弹出菜单。 - Sagar Chavada
显示剩余2条评论
3个回答

16

你需要展示一个带有列表的对话框。就像这样:

    itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            final CharSequence[] items = {"Supprimer", "etc", "etc1"};

            AlertDialog.Builder builder = new AlertDialog.Builder(mContext);

            builder.setTitle("Select The Action");
            builder.setItems(items, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int item) {
                }
            });
            builder.show();
            return true;
        }
    });

1
所以不需要registerContextMenu和相关方法吗?这个解决方案确实可以解决问题,即使我想尝试上下文菜单也是如此。 - Isabelle
没有必要,至少上次我使用上下文菜单是在3年前,而且我认为它并不实用。 - Divers
我最终选择了您的解决方案,这是我想要实现的最简单的方法。谢谢! - Isabelle
@Divers 完美解决方案,小巧优化。谢谢 :) - Luvnish Monga
1
如何在RecyclerView中获取所选项目? - hguser

2

被接受的答案并不是技术上的“答案”,它实际上是一个巧妙的解决方法,因为它创建了一个 AlertDialog 而不是 OP 请求的 ContextMenu,它确实“解决了要求”,但它并没有创建 ContextMenu

这是我找到的最短实现:

在 Activity 中像往常一样进行重写:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    menu.add("do this");
    menu.add("do that");
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    if (item.getTitle().equals("do this") {
        // do whatever this...
    }
    else if (item.getTitle().equals("do that") {
        // do whatever that...
    }
    return super.onContextItemSelected(item);
}

在RecyclerView的item ViewHolder中:

private class ItemViewHolder extends RecyclerView.ViewHolder {
    ...
    private ItemViewHolder(@NonNull View pItemView) {
        super(pItemView);
        pItemView.setLongClickable(true); // <-- make long clickable
        ...
    }
}

在Activity的onCreate方法中:

registerForContextMenu(myRecyclerView);

因为没有获取长按哪个项目的逻辑,所以被踩了!ContextMenu在Activity Context中,而LongClick在Adapter中。 - Bhavik Mehta
它就在上面的.onContextItemSelected()事件处理程序中 - 很明显。在活动上调用.registerForContextMenu()会将RecyclerView与上面定义的事件处理程序注册起来。事件处理程序不必在适配器内部,实际上它可以完全在一个单独的类中。顺便说一下,这也是经过充分测试的代码,样本取自生产应用程序之一。 - AlexVPerl
@AlexVPerl 对的,但如果我们有一个人员回收站,我们如何在onContextItemSelected()中获取长按的人员名称? - Chris Happy

0

编辑1:要显示对话框,请使用

 openContextMenu(v);

v指的是视图。

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
                                ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.context_menu,menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
  int id = item.getItemId();
        default:
            return super.onContextItemSelected(item);
    }
}

菜单文件夹中context_menu文件中的代码应该如下所示:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.example.MainActivity">

    <item
        android:id="@+id/item"
        android:orderInCategory="200"
        android:title="Item"
        android:icon="@drawable/faq"
        app:showAsAction="ifRoom"
        ></item>
</menu>

过去,我也曾遇到RecyclerView的onClickListener和onLongClickListener的一些问题。所以这是我正在使用的代码:
public class ItemClickSupport {
    private final RecyclerView mRecyclerView;
    private OnItemClickListener mOnItemClickListener;
    private OnItemLongClickListener mOnItemLongClickListener;
    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mOnItemClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
                mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
            }
        }
    };
    private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            if (mOnItemLongClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
                return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
            }
            return false;
        }
    };
    private RecyclerView.OnChildAttachStateChangeListener mAttachListener
            = new RecyclerView.OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(View view) {
            if (mOnItemClickListener != null) {
                view.setOnClickListener(mOnClickListener);
            }
            if (mOnItemLongClickListener != null) {
                view.setOnLongClickListener(mOnLongClickListener);
            }
        }

        @Override
        public void onChildViewDetachedFromWindow(View view) {

        }
    };

    private ItemClickSupport(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
        mRecyclerView.setTag(R.id.item_click_support, this);
        mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
    }

    public static ItemClickSupport addTo(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
        if (support == null) {
            support = new ItemClickSupport(view);
        }
        return support;
    }

    public static ItemClickSupport removeFrom(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
        if (support != null) {
            support.detach(view);
        }
        return support;
    }

    public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
        mOnItemClickListener = listener;
        return this;
    }

    public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
        mOnItemLongClickListener = listener;
        return this;
    }

    private void detach(RecyclerView view) {
        view.removeOnChildAttachStateChangeListener(mAttachListener);
        view.setTag(R.id.item_click_support, null);
    }

    public interface OnItemClickListener {

        void onItemClicked(RecyclerView recyclerView, int position, View v);
    }

    public interface OnItemLongClickListener {

        boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
    }
}

然后在Activity中,使用以下代码:

ItemClickSupport.addTo(recyclerView).setOnItemLongClickListener(new ItemClickSupport.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {

                return true;
            }
    });

使用position来指定项目。希望能够帮到你!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接