Créer le Menu Options pour RecyclerView-Item

comment créer un Menu Options comme dans la capture D'écran suivante:

enter image description here

le Menu Options doit être ouvert après avoir cliqué sur L'icône"Plus" d'un article RecyclerView!

Mon essai était ceci:

@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();
        }
    });
}

mais cela cause des problèmes parce que l'article complet est cliqué si j'appuie sur le bouton RecyclerView Item More -...

<!-Voici mon Recycleurviewontouchlistener:

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);
    }
}

Je ne l'étais pas capable de trouver n'importe quel problème semblable donc j'espère que vous pouvez m'aider!

31
demandé sur the_dani 2016-06-02 23:17:45

6 réponses

il est très facile de créer un menu d'options comme celui-ci. Il suffit d'ajouter un bouton dans votre liste d'élément de conception. Vous pouvez utiliser la chaîne suivante pour afficher 3 points verticaux.

<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" />
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();

    }
});

c'est tout.

Source: Menu Options Pour RecyclerView Item

39
répondu Shaba Aafreen 2018-05-04 11:25:35

j'ai découvert que le seul Menu, qui ressemble au Menu ci-dessus est le 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);
    }
}

vous devez faire passer la méthode onClick à MotionEvent et enfin implémenter la méthode isViewClicked dans votre Recycleurviewontouchlistener:

public static boolean isViewClicked(View view, MotionEvent e) {
    Rect rect = new Rect();

    view.getGlobalVisibleRect(rect);

    return rect.contains((int) e.getRawX(), (int) e.getRawY());
}
8
répondu the_dani 2016-06-05 15:32:13

Changer RecyclerViewOnTouchListener classe pour passer le MotionEventOnTouchCallback mise en œuvre.

Dans la classe implémentant onItemClick, ajouter ce qui suit:

    @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 est la suivante:

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

Pour afficher une liste d'éléments ancrés à une vue (la touche menu), utilisez ListPopupWindow

2
répondu marmor 2016-06-05 16:11:22

étape.1 Ajouter la disposition de vue Recyclerview.

étape.2 Recyclerview lignes de mise en page 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>

Étape 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();
    }

}

étape.4 Présentation du menu 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>

étape.5 ajouter Classe Recycleremclicklistener.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
    }
}

étape.6 Ajouter ItemTouchListener sur Recyclerview.

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);
                            }
                        });
                    }
                })
        );
    } 

étape.4 créer le menu contextuel.

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
répondu kapoor 2016-06-09 09:24:54
  1. il y a une façon simple de montrer un menu comme celui-ci:

    ViewHolder: définir les champs

    private ImageView menuBtn;
    private PopupMenu popupMenu;
    

Créer une méthode bind avec la logique de créer le menu sur le bouton cliquer et le fermer sur réutiliser la vue:

    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();
            }
        });

Méthode createMenu(Menu menu) est à vous, ici, est simple exemple:

 menu.add("Menu title")
     .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    // do whatever you want
                }
            });
  1. pour la manipulation cliquez sur autre partie de l'élément de la liste que vous n'avez pas besoin de définir OnItemTouchListener du point de vue du recycleur, mais simple en méthode onBindViewHolder faire:

    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
            }
        });
    
0
répondu Jin35 2016-06-10 11:07:49

Toutes les réponses ci-dessus sont grands. Je veux juste ajouter un petit pourboire. faisant le bouton "plus" avec textView est aussi une bonne solution, mais il y a un moyen plus pratique de le faire. vous pouvez obtenir le vecteur actif de vecteur d'actifs menu dans le studio android et utilisez cette ressource pour n'importe quel bouton ou vue où vous voulez.

//for instance 
//ic_more_vert_black_24dp.xml
<vector android:height="24dp" android:tint="#cccccc"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,8c1.1,0 2,-0.9 2,-2s- 
0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 
-0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
0
répondu Doongsil 2018-08-08 01:53:29