为RecyclerView-Item创build选项菜单

如何创build一个选项菜单,如下图所示:

在这里输入图像说明

选项菜单应该打开后再点击一个RecyclerView项目的“更多” – 图标!

我的尝试是这样的:

@Override public void onBindViewHolder(Holder holder, int position) { holder.txvSongTitle.setText(sSongs[position].getTitle()); holder.txvSongInfo.setText(sSongs[position].getAlbum() + " - " + sSongs[position].getArtist()); holder.btnMore.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, "More...", Toast.LENGTH_SHORT).show(); } }); } 

但是,这会导致问题,因为如果我点击RecyclerView项目更多button,点击完整的项目…

这是我的RecyclerViewOnTouchListener:

 public class RecyclerViewOnTouchListener implements RecyclerView.OnItemTouchListener { private GestureDetector mGestureDetector; private OnTouchCallback mOnTouchCallback; public RecyclerViewOnTouchListener(Context context, final RecyclerView recyclerView, final OnTouchCallback onTouchCallback) { mOnTouchCallback = onTouchCallback; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (child != null && onTouchCallback != null) { onTouchCallback.onLongClick(child, recyclerView.getChildLayoutPosition(child)); } super.onLongPress(e); } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { View child = rv.findChildViewUnder(e.getX(), e.getY()); if (child != null && mOnTouchCallback != null && mGestureDetector.onTouchEvent(e)) { mOnTouchCallback.onClick(child, rv.getChildLayoutPosition(child)); } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } public interface OnTouchCallback { void onClick(View view, int position); void onLongClick(View view, int position); } } 

我无法find任何类似的问题,所以我希望你能帮助我!

Solutions Collecting From Web of "为RecyclerView-Item创build选项菜单"

创build这样的选项菜单非常简单。 只需在列表项目devise中添加一个button。 您可以使用以下string来显示3个垂直点。

  <TextView android:id="@+id/textViewOptions" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:paddingLeft="@dimen/activity_horizontal_margin" android:text="&#8942;" android:textAppearance="?android:textAppearanceLarge" /> 

现在在你的适配器里面的onBindViewHolder()使用下面的代码。

 holder.buttonViewOption.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //creating a popup menu PopupMenu popup = new PopupMenu(mCtx, holder.buttonViewOption); //inflating menu from xml resource popup.inflate(R.menu.options_menu); //adding click listener popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.menu1: //handle menu1 click break; case R.id.menu2: //handle menu2 click break; case R.id.menu3: //handle menu3 click break; } return false; } }); //displaying the popup popup.show(); } }); 

而已。

来源: RecyclerView项目的选项菜单

我发现唯一的菜单,看起来像上面的菜单是PopupMenu

所以在onClick

 @Override public void onClick(View view, int position, MotionEvent e) { ImageButton btnMore = (ImageButton) view.findViewById(R.id.item_song_btnMore); if (RecyclerViewOnTouchListener.isViewClicked(btnMore, e)) { PopupMenu popupMenu = new PopupMenu(view.getContext(), btnMore); getActivity().getMenuInflater().inflate(R.menu.menu_song, popupMenu.getMenu()); popupMenu.show(); //The following is only needed if you want to force a horizontal offset like margin_right to the PopupMenu try { Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup"); fMenuHelper.setAccessible(true); Object oMenuHelper = fMenuHelper.get(popupMenu); Class[] argTypes = new Class[] {int.class}; Field fListPopup = oMenuHelper.getClass().getDeclaredField("mPopup"); fListPopup.setAccessible(true); Object oListPopup = fListPopup.get(oMenuHelper); Class clListPopup = oListPopup.getClass(); int iWidth = (int) clListPopup.getDeclaredMethod("getWidth").invoke(oListPopup); clListPopup.getDeclaredMethod("setHorizontalOffset", argTypes).invoke(oListPopup, -iWidth); clListPopup.getDeclaredMethod("show").invoke(oListPopup); } catch (NoSuchFieldException nsfe) { nsfe.printStackTrace(); } catch (NoSuchMethodException nsme) { nsme.printStackTrace(); } catch (InvocationTargetException ite) { ite.printStackTrace(); } catch (IllegalAccessException iae) { iae.printStackTrace(); } } else { MusicPlayer.playSong(position); } } 

你必须让你的onClick方法通过isViewClicked ,并最终在您的RecyclerViewOnTouchListener中实现方法isViewClicked

 public static boolean isViewClicked(View view, MotionEvent e) { Rect rect = new Rect(); view.getGlobalVisibleRect(rect); return rect.contains((int) e.getRawX(), (int) e.getRawY()); } 

更改RecyclerViewOnTouchListener类以将OnTouchCallback传递给OnTouchCallback实现。

在实现onItemClick的类中,添加以下内容:

  @Override public void onClick(final View view, int position, MotionEvent e) { View menuButton = view.findViewById(R.id.menu); if (isViewClicked(e, menuButton)) { menuButton.setOnCreateContextMenuListener(this); menuButton.showContextMenu(); return; } ... } 

其中isViewClicked是以下内容:

  private boolean isViewClicked(MotionEvent e, View view) { Rect rect = new Rect(); view.getGlobalVisibleRect(rect); return rect.contains((int) e.getRawX(), (int) e.getRawY()); } 

要显示锚定到视图(菜单button)的项目列表,请使用ListPopupWindow

step.1添加Recyclerview视图布局。

第2步RecyclerView行布局recycler_item.xml

 <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="8dp" card_view:cardCornerRadius="4dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/itemTextView" style="@style/Base.TextAppearance.AppCompat.Body2" android:layout_width="wrap_content" android:layout_height="?attr/listPreferredItemHeight" android:gravity="center_vertical" android:layout_centerVertical="true" android:padding="8dp" /> <ImageView android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:src="@mipmap/more" android:layout_alignParentRight="true" android:text="Button" android:padding="10dp" android:layout_marginRight="10dp"/> </RelativeLayout> </android.support.v7.widget.CardView> 

第3步。RecyclerAdapter

 public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List<String> mItemList; public RecyclerAdapter(List<String> itemList) { mItemList = itemList; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Context context = parent.getContext(); View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false); return RecyclerItemViewHolder.newInstance(view); } @Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { RecyclerItemViewHolder holder = (RecyclerItemViewHolder) viewHolder; String itemText = mItemList.get(position); holder.setItemText(itemText); } @Override public int getItemCount() { return mItemList == null ? 0 : mItemList.size(); } } 

step.4菜单布局navigation_drawer_menu_items.xml

 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/navigation_drawer_item1" android:icon="@android:drawable/ic_dialog_map" android:title="Item 1" /> <item android:id="@+id/navigation_drawer_item2" android:icon="@android:drawable/ic_dialog_info" android:title="Item 2" /> <item android:id="@+id/navigation_drawer_item3" android:icon="@android:drawable/ic_menu_share" android:title="Item 3"/> </menu> 

step.5添加RecyclerItemClickListener.java类

 import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { private OnItemClickListener mListener; public interface OnItemClickListener { void onItemClick(View view, int position); } GestureDetector mGestureDetector; public RecyclerItemClickListener(Context context, OnItemClickListener listener) { mListener = listener; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } }); } @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { View childView = view.findChildViewUnder(e.getX(), e.getY()); if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { mListener.onItemClick(childView, view.getChildAdapterPosition(childView)); } return false; } @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { // do nothing } } 

step.6在Recyclerview上添加ItemTouchListener。

 private void initRecyclerView() { RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); RecyclerAdapter recyclerAdapter = new RecyclerAdapter(createItemList()); recyclerView.setAdapter(recyclerAdapter); recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, final int position) { ImageView moreImage = (ImageView) view.findViewById(R.id.button); moreImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openOptionMenu(v,position); } }); } }) ); } 

step.4创buildpopup式菜单。

 public void openOptionMenu(View v,final int position){ PopupMenu popup = new PopupMenu(v.getContext(), v); popup.getMenuInflater().inflate(R.menu.navigation_drawer_menu_items, popup.getMenu()); popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { Toast.makeText(getBaseContext(), "You selected the action : " + item.getTitle()+" position "+position, Toast.LENGTH_SHORT).show(); return true; } }); popup.show(); } 
  1. 有一个简单的方法来显示这样的菜单:

    ViewHolder:定义字段

     private ImageView menuBtn; private PopupMenu popupMenu; 

创build方法bindbutton上的创build菜单的逻辑bind点击并closures重用视图:

  if (popupMenu != null) { popupMenu.dismiss(); } menuBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { popupMenu = new PopupMenu(v.getContext(), v); createMenu(popupMenu.getMenu()); popupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() { @Override public void onDismiss(PopupMenu menu) { popupMenu = null; } }); popupMenu.show(); } }); 

方法createMenu(Menu menu)取决于你,这里是简单的例子:

  menu.add("Menu title") .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { // do whatever you want } }); 
  1. 为了处理点击列表项的其他部分,您不需要在回收器视图上设置OnItemTouchListener ,但在方法onBindViewHolder可以简单地执行:

     holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //handle click here } }); holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { //handle long click here } });