Create Options Menu for RecyclerView-Item
How do I create an Options Menu like in the following Screenshot:
The Options Menu should be opened afther clicking on the "More"-Icon of a RecyclerView Item!
My try was this:
@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();
}
});
}
But this causes problems because the full item is clicked if I touch on the RecyclerView Item More-Button...
Here's my 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);
}
}
I wasn't able to find any similar problem so I hope you can help me!
Solution 1:
It is very easy to create an option menu like this. Just add a button in your list item design. You can use the following string to display 3 vertical dots.
<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="⋮"
android:textAppearance="?android:textAppearanceLarge" />
Now in your adapter inside onBindViewHolder() use the following code.
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
return true;
case R.id.menu2:
//handle menu2 click
return true;
case R.id.menu3:
//handle menu3 click
return true;
default:
return false;
}
}
});
//displaying the popup
popup.show();
}
});
Thats it.
Source: Options Menu For RecyclerView Item
Solution 2:
I found out that the only Menu, that looks like the Menu above is the PopupMenu
.
So in 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);
}
}
You have to make your onClick-Method pass the MotionEvent and finally implement the Method isViewClicked
in your RecyclerViewOnTouchListener:
public static boolean isViewClicked(View view, MotionEvent e) {
Rect rect = new Rect();
view.getGlobalVisibleRect(rect);
return rect.contains((int) e.getRawX(), (int) e.getRawY());
}