How to create context menu for RecyclerView

后端 未结 21 2578
日久生厌
日久生厌 2020-11-28 01:20

How do I implement context menu for RecyclerView? Apparently calling registerForContextMenu(recyclerView) doesn\'t work. I\'m calling it from a fra

相关标签:
21条回答
  • 2020-11-28 02:02

    I have combined my solution with the solution from @Hardik Shah:

    In the activity I have:

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        if (v.getId() == R.id.rvQuests) {
            getMenuInflater().inflate(R.menu.list_menu, menu);
        }
    }
    

    In the Adapter I have:

    private MainActivity context;
    private int position;
    
    public int getPosition() {
        return position;
    }
    
    public void setPosition(int position) {
        this.position = position;
    }
    
    public QuestsAdapter(MainActivity context, List<Quest> objects) {
        this.context = context;
        this.quests.addAll(objects);
    }
    
    public class QuestViewHolder extends RecyclerView.ViewHolder {
        private QuestItemBinding questItemBinding;
    
        public QuestViewHolder(View v) {
            super(v);
            questItemBinding = DataBindingUtil.bind(v);
            v.setOnCreateContextMenuListener(context);
        }
    }
    
    @Override
    public void onBindViewHolder(final QuestViewHolder holder, int position) {
        Quest quest = quests.get(position);
        holder.questItemBinding.setQuest(quest);
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                setPosition(holder.getAdapterPosition());
                return false;
            }
        });
    }
    
    @Override
    public void onViewRecycled(QuestViewHolder holder) {
        holder.itemView.setOnLongClickListener(null);
        super.onViewRecycled(holder);
    }
    

    In fragment I have:

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        int position = ((QuestsAdapter) questsList.getAdapter()).getPosition();
        switch (item.getItemId()) {
            case R.id.menu_delete:
                Quest quest = questsAdapter.getItem(position);
                App.getQuestManager().deleteQuest(quest);
                questsAdapter.remove(quest);
                checkEmptyList();
                return true;
            default:
                return super.onContextItemSelected(item);
        }
    }
    
    0 讨论(0)
  • 2020-11-28 02:04

    You can't directly implement these method like onClickListener, OnContextMenuListener etc. because RecycleView extends android.view.ViewGroup. So we cant directly use these method. We can implement these methods in ViewHolder adapter class. We can use context menu in RecycleView like this way:

    public static class ViewHolder extends RecyclerView.ViewHolder implements OnCreateContextMenuListener {
    
        TextView tvTitle;
        ImageView ivImage;
    
        public ViewHolder(View v) {
            super(v);
            tvTitle =(TextView)v.findViewById(R.id.item_title);
            v.setOnCreateContextMenuListener(this);
    
    
        }
    

    Now we follow the same procedure while implements the context menu.

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    
        menu.setHeaderTitle("Select The Action");    
        menu.add(0, v.getId(), 0, "Call");//groupId, itemId, order, title   
        menu.add(0, v.getId(), 0, "SMS"); 
    
    }
    

    If you get any difficulties ask in comment.

    0 讨论(0)
  • 2020-11-28 02:04

    Try this for a View item in recycleView

    .setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
            @Override
            public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
                menu.add("delete").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem item) {
    
                        //do what u want
                        return true;
                    }
                });
            }
        });
    

    You can use it with setting data to a ViewHolder item

    0 讨论(0)
  • 2020-11-28 02:06

    A solution for those who want to get item id when calling ContextMenu.

    If you have a RecyclerView with items like this (containing clickable ImageView):

    then you should receive callbacks from onClickListener.

    Adapter

    class YourAdapter(private val contextMenuCallback: ContextMenuCallback) :
        RecyclerView.Adapter<YourAdapter.ViewHolder>() {
    
        private var items: MutableList<Item> = mutableListOf()
    
        ...
    
        override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
            val item = items[position] as Item
            updateItem(viewHolder, item)
    
            setOnClickListener(viewHolder.itemView, items[position].id, items[position].title)
        }
    
        private fun setOnClickListener(view: View, id: Int, title: String) {
    //        view.setOnClickListener { v ->  }
            // A click listener for ImageView `more`.
            view.more.setOnClickListener {
                // Here we pass item id, title, etc. to Fragment.
                contextMenuCallback.onContextMenuClick(view, id, title)
            }
        }
    
    
        class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            val titleTextView: TextView = itemView.title
        }
    
        class Item(
            val id: Int,
            val title: String
        )
    
        interface ContextMenuCallback {
            fun onContextMenuClick(view: View, id: Int, title: String)
        }
    }
    

    Fragment

    class YourFragment : Fragment(), YourAdapter.ContextMenuCallback {
    
        private var adapter: YourAdapter? = null
        private var linearLayoutManager: LinearLayoutManager? = null
        private var selectedItemId: Int = -1
        private lateinit var selectedItemTitle: String
    
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            adapter = YourAdapter(this)
            view.recycler_view.apply {
                layoutManager = linearLayoutManager
                adapter = this@YourFragment.adapter
                setHasFixedSize(true)
            }
    
            registerForContextMenu(view.recycler_view)
        }
    
        override fun onCreateContextMenu(menu: ContextMenu?, v: View?,
                                         menuInfo: ContextMenu.ContextMenuInfo?) {
            activity?.menuInflater?.inflate(R.menu.menu_yours, menu)
        }
    
        override fun onContextItemSelected(item: MenuItem?): Boolean {
            super.onContextItemSelected(item)
            when (item?.itemId) {
                R.id.action_your -> yourAction(selectedItemId, selectedItemTitle)
                ...
            }
            return true
        }
    
        override fun onContextMenuClick(view: View, id: Int, title: String) {
            // Here we accept item id, title from adapter and show context menu.
            selectedItemId = id
            selectedItemTitle = title
            view.showContextMenu()
        }
    }
    

    Warning!

    If you use a ViewPager based on one fragment (all pages are similar lists), you will face a problem. When you override onContextItemSelected to understand what menu item was selected, you will get a list item id from the first page! To overcome this problem see Wrong fragment in ViewPager receives onContextItemSelected call.

    0 讨论(0)
  • 2020-11-28 02:06

    Ok, based from @Flexo's answer, I shall put mPosition to order...

    protected class ExampleViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {
    
        int mPosition;
    
        public KWViewHolder(View itemView) {
            super(itemView);
            itemView.setOnCreateContextMenuListener(this);
        }
    
        public void setPosition(int position) {
            mPosition = position;
        }
    
        @Override
        public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
            contextMenu.setHeaderTitle(R.string.menu_title_context);
            contextMenu.add(0, R.id.menu_delete, mPosition, R.string.delete);
        }
    }
    

    then in onContextItemSelected I use

    item.getOrder() 
    

    And all work fine I get array's position easily

    0 讨论(0)
  • 2020-11-28 02:07

    Here is a clean way to use menu context on RecyclerView items

    First, you need an item position

    In Adapter class:

     /**
     * Custom on long click item listener.
     */
    onLongItemClickListener mOnLongItemClickListener;
    
    public void setOnLongItemClickListener(onLongItemClickListener onLongItemClickListener) {
        mOnLongItemClickListener = onLongItemClickListener;
    }
    
    public interface onLongItemClickListener {
        void ItemLongClicked(View v, int position);
    }
    

    In onBindViewHolder hook the custom listener:

            // Hook our custom on long click item listener to the item view.
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if (mOnLongItemClickListener != null) {
                        mOnLongItemClickListener.ItemLongClicked(v, position);
                    }
    
                    return true;
                }
            });
    

    In MainActivity (Activity/Fragment) create a field:

    private int mCurrentItemPosition;
    

    In your Adapter object set the custom listener:

        mAdapter.setOnLongItemClickListener(new FileAdapter.onLongItemClickListener() {
            @Override
            public void ItemLongClicked(View v, int position) {
                mCurrentItemPosition = position;
            }
        });
    

    Now you have a yummy position for any item you long clicked on it

    0 讨论(0)
提交回复
热议问题