मैं RecyclerView?
जाहिरा तौर पर कॉल करने के लिए संदर्भ मेनू कैसे लागू registerForContextMenu(recyclerView)
नहीं करता है। मैं इसे एक टुकड़े से बुला रहा हूं। क्या किसी को भी इसे लागू करने में कोई सफलता मिली?
मैं RecyclerView?
जाहिरा तौर पर कॉल करने के लिए संदर्भ मेनू कैसे लागू registerForContextMenu(recyclerView)
नहीं करता है। मैं इसे एक टुकड़े से बुला रहा हूं। क्या किसी को भी इसे लागू करने में कोई सफलता मिली?
जवाबों:
आप सीधे की तरह इन विधि लागू नहीं कर सकते onClickListener , OnContextMenuListener आदि क्योंकि RecycleView फैली android.view.ViewGroup । तो हम सीधे इन विधि का उपयोग नहीं कर सकते। हम ViewHolder एडाप्टर क्लास में इन तरीकों को लागू कर सकते हैं । हम इस तरह से RecycleView में संदर्भ मेनू का उपयोग कर सकते हैं:
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);
}
अब हम संदर्भ मेनू को लागू करते समय उसी प्रक्रिया का पालन करते हैं।
@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");
}
अगर आपको टिप्पणी में कोई कठिनाई आती है।
onContextItemSelected
गतिविधि / खंड स्तर पर लागू करते हैं । getTitle
काम करता है, getItemId
काम करता है, लेकिन getMenuInfo
अशक्त करता है। तो, कैसे प्राप्त करने के लिए ViewHolder
?
getMenuInfo()
शून्य में वापस आता है onContextItemSelected()
। हो सकता है कि जिन लोगों ने इसे काम करने के लिए प्राप्त किया हो वे onCreateContextMenu()
आगे की पदानुक्रम ( RecyclerView
या Fragment
) के दृष्टिकोण में एक विधि हो ? यह काम कर सकता है लेकिन फिर हमें इस प्रश्न के अन्य उत्तरों में ले जाता है।
menu.add(this.getAdapterPosition(), v.getId(), 0, "Call");
लिए आप अपने कॉलबैक विधि परीक्षण में उपयोग कर सकते हैंitem.getGroupId()
जानकारी और टिप्पणियों के लिए धन्यवाद। मैं ContextMenu
आइटम के लिए प्राप्त करने में सक्षम था Recyclerview
।
मैंने जो किया था यह रहा
फ्रैगमेंट की onViewCreated
विधि या गतिविधि की onCreate
विधि में:
registerForContextMenu(mRecyclerView);
फिर एडेप्टर में जोड़ें
private int position;
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
बनाने ViewHolder
वर्ग को लागूOnCreateContextMenuListener
public static class ViewHolder extends RecyclerView.ViewHolder
implements View.OnCreateContextMenuListener {
public ImageView icon;
public TextView fileName;
public ImageButton menuButton;
public ViewHolder(View v) {
super(v);
icon = (ImageView)v.findViewById(R.id.file_icon);
fileName = (TextView)v.findViewById(R.id.file_name);
menuButton = (ImageButton)v.findViewById(R.id.menu_button);
v.setOnCreateContextMenuListener(this);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
//menuInfo is null
menu.add(Menu.NONE, R.id.ctx_menu_remove_backup,
Menu.NONE, R.string.remove_backup);
menu.add(Menu.NONE, R.id.ctx_menu_restore_backup,
Menu.NONE, R.string.restore_backup);
}
}
onBindViewHolder
OnLongClickListener
संदर्भ मेनू लोड होने से पहले स्थिति पर कब्जा करने के लिए धारक पर जोड़ें ।itemView:
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
setPosition(holder.getPosition());
return false;
}
});
फिर onViewRecycled
श्रोता हटा दें ताकि कोई संदर्भ समस्या न हो। (आवश्यकता नहीं हो सकती है)।
@Override
public void onViewRecycled(ViewHolder holder) {
holder.itemView.setOnLongClickListener(null);
super.onViewRecycled(holder);
}
अंत में इस खंड / गतिविधि में निम्नानुसार ओवरराइड करें onContextItemSelected
:
@Override
public boolean onContextItemSelected(MenuItem item) {
int position = -1;
try {
position = ((BackupRestoreListAdapter)getAdapter()).getPosition();
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage(), e);
return super.onContextItemSelected(item);
}
switch (item.getItemId()) {
case R.id.ctx_menu_remove_backup:
// do your stuff
break;
case R.id.ctx_menu_restore_backup:
// do your stuff
break;
}
return super.onContextItemSelected(item);
}
वर्तमान उत्तर सही नहीं है। यहां एक कार्यशील कार्यान्वयन है:
public class ContextMenuRecyclerView extends RecyclerView {
private RecyclerViewContextMenuInfo mContextMenuInfo;
@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
return mContextMenuInfo;
}
@Override
public boolean showContextMenuForChild(View originalView) {
final int longPressPosition = getChildPosition(originalView);
if (longPressPosition >= 0) {
final long longPressId = getAdapter().getItemId(longPressPosition);
mContextMenuInfo = new RecyclerViewContextMenuInfo(longPressPosition, longPressId);
return super.showContextMenuForChild(originalView);
}
return false;
}
public static class RecyclerViewContextMenuInfo implements ContextMenu.ContextMenuInfo {
public RecyclerViewContextMenuInfo(int position, long id) {
this.position = position;
this.id = id;
}
final public int position;
final public long id;
}
}
आपके टुकड़े (या गतिविधि) में:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRecyclerView = view.findViewById(R.id.recyclerview);
registerForContextMenu(mRecyclerView);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
// inflate menu
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.my_context_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
return super.onContextItemSelected(item);
RecyclerViewContextMenuInfo info = (RecyclerViewContextMenuInfo) item.getMenuInfo();
// handle menu item here
}
और अंत में, आपके ViewHolder में:
class MyViewHolder extends RecyclerView.View.ViewHolder {
...
private void onLongClick() {
itemView.showContextMenu();
}
}
getChildPosition()
अब पदावनत हो गया है। मैं getChildAdapterPosition()
इसके बजाय इस्तेमाल किया।
getChildPosition()
में पदावनत किया गया है com.android.support:recyclerview-v7:22.0.0
।
इसे View
पुनरावृत्ति में किसी आइटम के लिए आज़माएँ
.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;
}
});
}
});
आप किसी ViewHolder
आइटम पर डेटा सेट करने के साथ इसका उपयोग कर सकते हैं
प्रभाकर का उत्तर सही है, लेकिन उन्होंने यह नहीं बताया कि एक संदर्भ मेनू आइटम का चयन होने पर, दबाए गए आइटम से संबंधित डेटा कैसे प्राप्त किया जाए। हम onContextItemSelected
कॉलबैक का उपयोग कर सकते हैं , लेकिन इस मामले में ContextMenuInfo
उपलब्ध नहीं है ( null
) (यदि getContextMenuInfo()
एक दबाए गए दृश्य के लिए विधि को ओवरराइड नहीं किया गया है)। तो, सबसे सरल उपाय OnMenuItemClickListener
सीधे जोड़ना है MenuItem
।
private class ViewHolder extends RecyclerView.ViewHolder {
private final TextView mTitleTextView;
private MyItemData mData;
public ViewHolder(View view) {
super(view);
mTitleTextView = (TextView)view.findViewById(R.id.title);
view.setOnCreateContextMenuListener(mOnCreateContextMenuListener);
}
public void bind(@NonNull MyItemData data) {
mData = data;
String title = mData.getTitle();
mTitleTextView.setText(title);
}
private final View.OnCreateContextMenuListener mOnCreateContextMenuListener = new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
if (mData!= null) {
MenuItem myActionItem = menu.add("My Context Action");
myActionItem.setOnMenuItemClickListener(mOnMyActionClickListener);
}
}
};
private final MenuItem.OnMenuItemClickListener mOnMyActionClickListener = new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
//todo: process item click, mData is available here!!!
return true;
}
};
}
RecyclerView
केवल ओवरराइड getContextMenuInfo
इत्यादि के कस्टम उप-वर्ग बनाना नहीं चाहते हैं , भले ही यह टुकड़ा / गतिविधि को हैंडल क्लिक करने के रूप में काफी कुशल नहीं है। श्रोताओं के पास धारक में डेटा तक पहुंच होगी, इसलिए आपको स्थिति की आवश्यकता नहीं होनी चाहिए। और सैद्धांतिक रूप से आप अपने एडेप्टर में किसी भी तरह से बाध्यकारी होने पर स्थिति को कैश कर सकते हैं, और यदि आवश्यक हो तो अपने धारक से कॉल करने के लिए प्रतिनिधिमंडल का उपयोग कर सकते हैं, हालांकि Context
बाध्य विचारों में से एक का उपयोग करना कभी-कभी पर्याप्त हो सकता है।
@ रेनॉड के जवाब ने मेरे लिए काम किया लेकिन पहले कई कोड फिक्स की आवश्यकता थी। यह ऐसा है जैसे उसने अपने कोड के कई अलग-अलग पुनरावृत्तियों से स्निपेट पोस्ट किए हैं। जिन बदलावों की आवश्यकता है, वे हैं:
RecyclerContextMenuInfo
तथा RecyclerViewContextMenuInfo
एक ही वर्ग हैं। एक नाम चुनें और उसके साथ रहें।ViewHolder
को लागू करना चाहिए View.OnLongClickListener
, और कॉल करने के लिए याद setOnLongClickListener()
निर्माता में आइटम पर।onLongClick()
श्रोता, getView().showContextMenu()
पूरी तरह से गलत है। आपको showContextMenuForChild()
अपने में कॉल करना होगा ContextMenuRecyclerView
, अन्यथा ContextMenuInfo
आप अंदर पहुंच जाएंगे onCreateContextMenu()
और onContextItemSelected()
अशक्त हो जाएंगे।नीचे मेरा संपादित कोड:
ContextMenuRecyclerView:
public class ContextMenuRecyclerView extends RecyclerView {
private RecyclerViewContextMenuInfo mContextMenuInfo;
@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
return mContextMenuInfo;
}
@Override
public boolean showContextMenuForChild(View originalView) {
final int longPressPosition = getChildPosition(originalView);
if (longPressPosition >= 0) {
final long longPressId = getAdapter().getItemId(longPressPosition);
mContextMenuInfo = new RecyclerViewContextMenuInfo(longPressPosition, longPressId);
return super.showContextMenuForChild(originalView);
}
return false;
}
public static class RecyclerViewContextMenuInfo implements ContextMenu.ContextMenuInfo {
public RecyclerViewContextMenuInfo(int position, long id) {
this.position = position;
this.id = id;
}
final public int position;
final public long id;
}
}
आपके टुकड़े में:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRecyclerView = view.findViewById(R.id.recyclerview);
registerForContextMenu(mRecyclerView);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
// inflate menu here
// If you want the position of the item for which we're creating the context menu (perhaps to add a header or something):
int itemIndex = ((ContextMenuRecyclerView.RecyclerViewContextMenuInfo) menuInfo).position;
}
@Override
public boolean onContextItemSelected(MenuItem item) {
ContextMenuRecyclerView.RecyclerViewContextMenuInfo info = (ContextMenuRecyclerView.RecyclerViewContextMenuInfo) item.getMenuInfo();
// handle menu here - get item index or ID from info
return super.onContextItemSelected(item);
}
आपके ViewHolder में:
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener {
public MyViewHolder( View itemView ) {
super( itemView );
itemView.setOnLongClickListener( this );
}
@Override public boolean onLongClick() {
recyclerView.showContextMenuForChild( v );
return true;
}
}
इसके अलावा, सुनिश्चित करें कि आप की जगह बनाने के RecyclerView
साथ ContextMenuRecyclerView
अपने लेआउट में!
recyclerView.showContextMenuForChild(itemView);
से itemView.showContextMenu()
।
एडाप्टर क्लास में:
/**
* Custom on long click item listener.
*/
onLongItemClickListener mOnLongItemClickListener;
public void setOnLongItemClickListener(onLongItemClickListener onLongItemClickListener) {
mOnLongItemClickListener = onLongItemClickListener;
}
public interface onLongItemClickListener {
void ItemLongClicked(View v, int position);
}
में onBindViewHolder
हुक कस्टम श्रोता:
// 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;
}
});
MainActivity (गतिविधि / टुकड़ा) में एक क्षेत्र बनाएँ:
private int mCurrentItemPosition;
अपने एडेप्टर ऑब्जेक्ट में कस्टम श्रोता सेट करें:
mAdapter.setOnLongItemClickListener(new FileAdapter.onLongItemClickListener() {
@Override
public void ItemLongClicked(View v, int position) {
mCurrentItemPosition = position;
}
});
अब आपके पास किसी भी आइटम के लिए एक यम्मी स्थिति है जिसे आपने लंबे समय पर क्लिक किया है
Res में -> मेनू
अपने मेनू आइटम एक फ़ाइल contai बनाएँ context_menu_main.xml
:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/delete" android:title="Delete"/>
<item android:id="@+id/share" android:title="Share"/>
</menu>
मुख्यता में:
दोनों को लागू करें onCreateContextMenu
और onContextItemSelected
:
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu_main, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.delete) {
}
if (id == R.id.share) {
}
return true;
}
संदर्भ मेनू दिखाएं।
registerForContextMenu(mRecyclerView);
mAdapter.setOnLongItemClickListener(new FileAdapter.onLongItemClickListener() {
@Override
public void ItemLongClicked(View v, int position) {
mCurrentItemPosition = position;
v.showContextMenu();
}
});
आशा है कि मैं कुछ भी नहीं भूलूंगा 🤔
मेंस प्रलेखन पर अधिक जानकारी
यहाँ कोटलिन के साथ ऐसा करने का एक सरल तरीका है जो मेरे लिए काम करता है। प्रमुख चुनौती उस आइटम की स्थिति का पता लगा रही है जिसे दबाया गया था। अपने एडेप्टर के अंदर, आप इस कोड स्निपेट को रख सकते हैं और यह उस आइटम की स्थिति को कैप्चर करने में सक्षम होगा जिसके लिए संदर्भ मेनू दिखाया गया है; बस इतना ही।
override fun onBindViewHolder(holder: YourViewHolder, position: Int) {
...
holder.view.setOnCreateContextMenuListener { contextMenu, _, _ ->
contextMenu.add("Add").setOnMenuItemClickListener {
longToast("I'm pressed for the item at position => $position")
true
}
}
}
मैंने अपने समाधान को @ हार्दिक शाह के समाधान के साथ जोड़ा है:
मेरे पास गतिविधि में:
@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);
}
}
एडाप्टर में मेरे पास है:
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);
}
मेरे पास टुकड़े में:
@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);
}
}
मुझे शायद पार्टी में देर हो गई है लेकिन मेरे पास काम करने का हल है । मैंने इसके लिए एक जिस्ट बनाया है।
संदर्भ मेनू को RecyclerView में जोड़ें
ActivityName.java
//Import Statements
public class ActivityName extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_birthdays);
//Recycle View
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mLayoutManager = new LinearLayoutManager(getApplicationContext());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new BirthdaysListAdapter(data, this);
mRecyclerView.setAdapter(mAdapter);
}
RecyclerAdapter.java
//Import Statements
public class BirthdaysListAdapter extends RecyclerView.Adapter<BirthdaysListAdapter.ViewHolder> {
static Context ctx;
private List<typeOfData> Data;
public BirthdaysListAdapter(List<typeOfData> list, Context context) {
Data = list;
this.ctx = context;
}
BirthdaysListAdapter() {
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {
public TextView name;
public TextView Birthday;
public ImageView colorAlphabet;
public TextView textInImg;
public ViewHolder(View v) {
super(v);
name = (TextView) v.findViewById(R.id.name);
Birthday = (TextView) v.findViewById(R.id.Birthday);
colorAlphabet = (ImageView) v.findViewById(R.id.colorAlphabet);
textInImg = (TextView) v.findViewById(R.id.textInImg);
v.setOnCreateContextMenuListener(this); //REGISTER ONCREATE MENU LISTENER
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v //CREATE MENU BY THIS METHOD
ContextMenu.ContextMenuInfo menuInfo) {
new BirthdaysListAdapter().info = (AdapterView.AdapterContextMenuInfo) menuInfo;
MenuItem Edit = menu.add(Menu.NONE, 1, 1, "Edit");
MenuItem Delete = menu.add(Menu.NONE, 2, 2, "Delete");
Edit.setOnMenuItemClickListener(onEditMenu);
Delete.setOnMenuItemClickListener(onEditMenu);
}
//ADD AN ONMENUITEM LISTENER TO EXECUTE COMMANDS ONCLICK OF CONTEXT MENU TASK
private final MenuItem.OnMenuItemClickListener onEditMenu = new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
DBHandler dbHandler = new DBHandler(ctx);
List<WishMen> data = dbHandler.getWishmen();
switch (item.getItemId()) {
case 1:
//Do stuff
break;
case 2:
//Do stuff
break;
}
return true;
}
};
}
public List<ViewBirthdayModel> getData() {
return Data;
}
@Override
public long getItemId(int position) {
return super.getItemId(position);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_view_birthdays, parent, false);
ViewHolder vh = new ViewHolder(view);
return vh;
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.name.setText(Data.get(position).getMan().getName());
holder.Birthday.setText(Data.get(position).getMan().getBday());
holder.colorAlphabet.setBackgroundColor(Color.parseColor(Data.get(position).getColor()));
holder.textInImg.setText(String.valueOf(Data.get(position).getMan().getName().toUpperCase().charAt(0)));
}
@Override
public int getItemCount() {
return Data.size();
}
private int position;
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
}
नमस्कार दोस्तों एक विकल्प के साथ आया जो मेरे लिए काम करता है। मैं सिर्फ अपना आइटम दृश्य रजिस्टरकेनटेक्स्टमेनू y व्यूहॉल्डर कंस्ट्रक्टर के साथ रजिस्टर करता हूं, उसी दृश्य पर एक ऑन लाइनक्लाइकलिस्टर भी सेट करता हूं। OnLongClick (देखें v) के कार्यान्वयन में, मुझे साधारण रूप से getLayoutPosition () के साथ क्लिक की गई स्थिति मिलती है और एक इंस्टेंस वेरिएबल में सहेजते हैं (मैंने इस डेटा का प्रतिनिधित्व करने के लिए एक वर्ग बनाया है, जैसे ContextMenuInfo के काम करने की उम्मीद है), लेकिन अधिक महत्वपूर्ण बनाना है सुनिश्चित करें कि आप इस विधि में गलत लौटें । सभी यो अब आपको onContextItemSelected (MenuItem आइटम) पर करना है, उस डेटा को पढ़ें जिसे आप अपने इंस्टा चर में संग्रहीत करते हैं और यदि यह मान्य है तो आप अपने कार्यों के साथ आगे बढ़ते हैं। यहाँ यह एक स्निपेट है।
public MyViewHolder(View itemView){
super(itemView);
registerForContextMenu(itemView);
itemView.setOnLongClickListener(this);
}
मैं ViewHolder को OnLongClickListener लागू करता हूं, लेकिन आप इसे किसी भी तरह से पसंद कर सकते हैं।
@Override
public boolean onLongClick(View v){
mCurrentLongItem = new ListItemInfo(v.getId(), getLayoutPosition());
return false; // REMEMBER TO RETURN FALSE.
}
आप इसे एडॉप्टर में भी सेट कर सकते हैं, या ViewHolder (यानी एक टेक्स्ट व्यू) में आपके पास मौजूद किसी अन्य व्यू के लिए। महत्वपूर्ण onLongClik () कार्यान्वयन है।
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.client_edit_context_menu:
if(mCurrentLongItem != null){
int position = mCurrentLongItem.position;
//TAKE SOME ACTIONS.
mCurrentLongItem = null;
}
return true;
}
return super.onContextItemSelected(item);
}
सबसे अच्छी बात यह है कि आप अभी भी उन मामलों में सही लौटे लॉन्गक्लिक ईवेंट को संसाधित कर सकते हैं, जो आप चाहते हैं, और कॉन्टेक्स्टमेनू को मिटा देगा।
यह विधि काम करती है क्योंकि registerForContextView व्यू लॉन्गक्लिक को बनाता है, और जब कॉन्टेक्स्टमेन्यू को प्रोसेस करने का समय आता है, तो सिस्टम performLongClick को कॉल करता है, जो पहले onLongClick इंप्लीमेंटेशन को कॉल करता है, और यदि यह गलत है, तो यह showContextMenu कहता है।
मैं कुछ समय के लिए इस समाधान का उपयोग कर रहा हूं और मेरे लिए बहुत अच्छा काम किया है।
public class CUSTOMVIEWNAME extends RecyclerView {
public CUSTOMVIEWNAME(Context context) {
super(context);
}
public CUSTOMVIEWNAME (Context context, AttributeSet attrs) {
super(context, attrs);
}
public CUSTOMVIEWNAME (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private RecyclerContextMenuInfo mContextMenuInfo;
@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
return mContextMenuInfo;
}
@Override
public boolean showContextMenuForChild(View originalView) {
final int longPressPosition = getChildAdapterPosition(originalView);
if (longPressPosition >= 0) {
final long longPressId = getAdapter().getItemId(longPressPosition);
mContextMenuInfo = new RecyclerContextMenuInfo(longPressPosition, ` longPressId);
return super.showContextMenuForChild(originalView);
}
return false;
}
public class RecyclerContextMenuInfo implements ContextMenu.ContextMenuInfo {
public RecyclerContextMenuInfo(int position, long id) {
this.position = position;
this.id = id;
}
final public int position;
final public long id;
}
}
अब आपके टुकड़े या गतिविधि में निम्नलिखित विधियों को लागू करें।
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
// Inflate Menu from xml resource
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.context_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
ContextMenuRecyclerView.RecyclerContextMenuInfo info = (ContextMenuRecyclerView.RecyclerContextMenuInfo) item.getMenuInfo();
Toast.makeText(InstanceOfContext , " User selected " + info.position, Toast.LENGTH_LONG).show();
return false;
}
अंत में recyclerview पर संदर्भ के लिए रजिस्टर करें
//for showing a popup on LongClick of items in recycler.
registerForContextMenu(recyclerView);
वह काम करना चाहिए!
यहां बताया गया है कि आप RecyclerView के लिए संदर्भ मेनू कैसे लागू कर सकते हैं, और आइटम की स्थिति प्राप्त कर सकते हैं, जिसके लिए संदर्भ मेनू आइटम का चयन किया गया है:
public class YourAdapter extends RecyclerView.Adapter<YourAdapter.ViewHolder> {
...
@Override
public void onBindViewHolder(@NonNull final ViewHolder viewHolder, int position) {
...
viewHolder.itemView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.add(0, R.id.mi_context_disable, 0, R.string.text_disable)
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
// can do something with item at position given below,
// viewHolder is final
viewHolder.getAdapterPosition();
return true;
}
});
menu.add(0, R.id.mi_context_remove, 1, R.string.text_remove)
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
// can do something with item at position given below,
// viewHolder is final
viewHolder.getAdapterPosition();
return true;
}
});
}
});
}
static class ViewHolder extends RecyclerView.ViewHolder {
private View itemView;
private ViewHolder(@NonNull View itemView) {
super(itemView);
this.itemView = itemView;
}
}
}
उन लोगों के लिए एक समाधान जो कॉल करते समय आइटम आईडी प्राप्त करना चाहते हैं ContextMenu
।
यदि आपके पास RecyclerView
इस तरह के आइटम हैं (क्लिक करने योग्य ImageView
):
फिर आपको कॉलबैक प्राप्त करना चाहिए onClickListener
।
अनुकूलक
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)
}
}
टुकड़ा
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()
}
}
चेतावनी!
यदि आप ViewPager
एक टुकड़े के आधार पर उपयोग करते हैं (सभी पृष्ठ समान सूचियां हैं), तो आपको एक समस्या का सामना करना पड़ेगा। जब आप onContextItemSelected
यह समझने में चूक जाते हैं कि कौन सा मेनू आइटम चुना गया था, तो आपको पहले पृष्ठ से एक सूची आइटम आईडी मिलेगा! इस समस्या को दूर करने के लिए ViewPager में गलत टुकड़ा onContextItemSelected कॉल प्राप्त करता है ।
मैं इस पर संघर्ष कर रहा हूं क्योंकि एंड्रॉइड मेरे लिए RecyclerView में यह अच्छी तरह से नहीं संभालता है, जो लिस्ट व्यू के लिए बहुत अच्छा काम कर रहा था।
सबसे मुश्किल टुकड़ा यह है कि ContextMenuInfo टुकड़ा एक View के अंदर एम्बेड किया गया है, जिसे आप आसानी से View को ओवरराइड करने के अलावा अन्य को संलग्न नहीं कर सकते हैं।
इसलिए आपको एक रैपर की आवश्यकता होगी जो गतिविधि को स्थिति की जानकारी देने में आपकी मदद करे।
public class RecyclerContextMenuInfoWrapperView extends FrameLayout {
private RecyclerView.ViewHolder mHolder;
private final View mView;
public RecyclerContextMenuInfoWrapperView(View view) {
super(view.getContext());
setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
mView = view;
addView(mView);
}
public void setHolder(RecyclerView.ViewHolder holder) {
mHolder = holder;
}
@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
return new RecyclerContextMenuInfo(mHolder.getPosition(), mHolder.getItemId());
}
public static class RecyclerContextMenuInfo implements ContextMenu.ContextMenuInfo {
public RecyclerContextMenuInfo(int position, long id) {
this.position = position;
this.id = id;
}
final public int position;
final public long id;
}
}
तब आपके RecyclerAdapter में, जब आप ViewHolders बनाते हैं, तो आपको Wrapper को रूट दृश्य के रूप में सेट करने की आवश्यकता होती है, और प्रत्येक दृश्य पर ReferenceMenu पंजीकृत करें।
public static class AdapterViewHolder extends RecyclerView.ViewHolder {
public AdapterViewHolder( View originalView) {
super(new RecyclerContextMenuInfoWrapperView(originalView);
((RecyclerContextMenuInfoWrapperView)itemView).setHolder(this);
yourActivity.registerForContextMenu(itemView);
itemView.setOnCreateContextMenuListener(yourListener);
}
}
और अंत में, आपकी गतिविधि में, आप वही कर पाएंगे जो आप आमतौर पर करते हैं:
@Override
public boolean onContextItemSelected(MenuItem item) {
int position = ((RecyclerContextMenuInfoWrapperView.RecyclerContextMenuInfo)item.getMenuInfo()).position;
// do whatever you need as now you have access to position and id and everything
सबसे अच्छा यह था कि आप पुनर्नवीनीकरण दृश्य के साथ संदर्भ मेनू का उपयोग करें यदि आप एक कस्टम पुनर्नवीनीकरण दृश्य बनाते हैं और getContextMenuInfo()
विधि को ओवरराइड करते हैं और संदर्भ मेनू जानकारी ऑब्जेक्ट के अपने स्वयं के इंस्टेंस को वापस करते हैं ताकि आप पदों को तब प्राप्त कर सकें जब इसे बनाया गया था और जब मेनू क्लिक किया गया है:
@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
return mContextMenuInfo;
}
मेरे द्वारा बनाए गए इस जिस्ट पर एक नज़र डालें:
थोड़े से ऊपर के कुछ उत्तरों पर विस्तार करते हुए, यदि आप एडॉप्टर / ViewHolder में अपने कोड में मेनू को मैन्युअल रूप से परिभाषित करने से बचना चाहते हैं तो आप एक पॉपअपमेनु का उपयोग कर सकते हैं और मेनू विकल्पों को एक मानक मेनू.xml संसाधन फ़ाइल से फुला सकते हैं।
नीचे दिए गए उदाहरण से यह पता चलता है कि श्रोता को पास करने की क्षमता भी शामिल है जिसे आप संदर्भ मेनू क्लिक का जवाब देने के लिए अपने Fragment / गतिविधि में लागू कर सकते हैं।
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private List<CustomObject> objects;
private OnItemSelectedListener listener;
private final boolean withContextMenu;
class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnCreateContextMenuListener, PopupMenu.OnMenuItemClickListener {
@BindView(R.id.custom_name)
TextView name;
@BindView(R.id.custom_value)
TextView value;
ViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
view.setOnClickListener(this);
if (withContextMenu) {
view.setOnCreateContextMenuListener(this);
}
}
@Override
public void onClick(View v) {
int position = getAdapterPosition();
if (listener != null) {
listener.onCustomerSelected(objects.get(position));
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
PopupMenu popup = new PopupMenu(v.getContext(), v);
popup.getMenuInflater().inflate(R.menu.custom_menu, popup.getMenu());
popup.setOnMenuItemClickListener(this);
popup.show();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
if (listener != null) {
CustomObject object = objects.get(getAdapterPosition());
listener.onCustomerMenuAction(object, item);
}
return false;
}
}
public CustomerAdapter(List<CustomObject> objects, OnItemSelectedListener listener, boolean withContextMenu) {
this.listener = listener;
this.objects = objects;
this.withContextMenu = withContextMenu;
}
public interface OnItemSelectedListener {
void onSelected(CustomObject object);
void onMenuAction(CustomObject object, MenuItem item);
}
@Override
public CustomerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.snippet_custom_object_line, parent, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(CustomAdapter.ViewHolder holder, int position) {
CustomObject object = objects.get(position);
holder.name.setText(object.getName());
holder.value.setText(object.getValue());
}
@Override
public int getItemCount() {
return objects.size();
}
}
यहां पूरी जानकारी दें। https://gist.github.com/brettwold/45039b7f02ce752ae0d32522a8e2ad9c
आप OnCreateContextMenuListener को बाइंड पर ViewHolder में पास कर सकते हैं। यह श्रोता डेटा के प्रत्येक आइटम के लिए कस्टम मेनू बना सकता है। बस अपने ViewHolder में setOnCreateContextMenuListener जोड़ें और बाध्यकारी के दौरान इसे कॉल करें।
public static class ItemViewHolder extends RecyclerView.ViewHolder
{
public ItemViewHolder(View itemView) {
super(itemView);
}
void setOnCreateContextMenuListener(View.OnCreateContextMenuListener listener) {
itemView.setOnCreateContextMenuListener(listener);
}
}
एडॉप्टर में:
@Override
public void onBindViewHolder(ItemViewHolder viewHolder,
int position) {
final MyObject myObject = mData.get(position);
viewHolder.setOnCreateContextMenuListener(new OnCreateContextMenuListener(){
@Override
public void onCreateContextMenu(ContextMenu menu,
View v, ContextMenuInfo menuInfo) {
switch (myObject.getMenuVariant() {
case MNU_VARIANT_1:
menu.add(Menu.NONE, CTX_MNU_1,
Menu.NONE,R.string.ctx_menu_item_1);
menu.add(Menu.NONE, CTX_MNU_2,Menu.NONE, R.string.ctx_menu_item_2);
break;
case MNU_VARIANT_2:
menu.add(Menu.NONE, CTX_MNU_3,Menu.NONE, R.string.ctx_menu_item_3);
break;
default:
menu.add(Menu.NONE, CTX_MNU_4,
Menu.NONE, R.string.ctx_menu_item_4);
}
}
});
}
मेरे मामले में मुझे onContextItemSelected()
विधि में अपने टुकड़े से डेटा का उपयोग करना था । जिस समाधान के साथ मैं जा रहा था वह मेरे एडाप्टर में टुकड़े का एक उदाहरण पारित करने और दृश्य धारक में दृश्य आइटम को पंजीकृत करने के लिए था:
@Override
public void onBindViewHolder(final MyListAdapter.ViewHolder viewHolder, int position) {
final Object rowObject = myListItems.get(position);
// Do your data binding here
viewHolder.itemView.setTag(position);
fragment.registerForContextMenu(viewHolder.itemView);
}
फिर onCreateContextMenu()
आप एक स्थानीय चर में सूचकांक को बचा सकते हैं:
selectedViewIndex = (int)v.getTag();
और इसे पुनः प्राप्त करें onContextItemSelected()
पहली बार जब मैं सामान्य एडेप्टर के साथ इस समस्या में भाग गया, तो मैंने अपना स्वयं का कस्टम व्यू सबक्लास तैयार किया और उसमें मेरी ज़रूरत का सामान जमा कर दिया। मैं वास्तव में उस समाधान को पसंद नहीं करता था और लोगों द्वारा प्रस्तावित किए गए महान विचारों को देखने के लिए बहुत समय बिताया था, और फैसला किया कि मुझे उन्हें कोई बेहतर नहीं लगा। इसलिए मैंने सब कुछ एक साथ रखा, थोड़ी देर के लिए इसे चारों ओर हिला दिया, और कुछ नया लेकर आया जो मुझे पसंद है।
हम एक जोड़ी उपयोगिता वर्गों के साथ शुरू करते हैं। संदर्भ मेनू को संभालने के लिए जो भी वस्तु जा रही है, उसके लिए ContextMenuHandler एक इंटरफ़ेस है। व्यवहार में, यह एक ViewHolder उपवर्ग होने जा रहा है, लेकिन सिद्धांत रूप में यह कुछ भी हो सकता है
/**
* Interface for objects that wish to create and handle selections from a context
* menu associated with a view
*/
public interface ContextMenuHandler extends View.OnCreateContextMenuListener {
boolean onContextItemSelected(MenuItem item);
}
अगला एक इंटरफ़ेस है जिसे किसी भी दृश्य द्वारा कार्यान्वित किया जाना है जो कि RecyclerView के तत्काल बच्चे के रूप में उपयोग होने वाला है।
public interface ViewWithContextMenu {
public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler);
public ContextMenuHandler getContextMenuHandler();
}
इसके बाद, किसी भी दृश्य जो एक RecylcerView के बच्चे के रूप में एक संदर्भ मेनू बनाने जा रहा है, उसे ViewWIthContextMenu को लागू करना होगा। मेरे मामले में, मुझे केवल रैखिकअरआउट के उपवर्ग की आवश्यकता थी।
public class LinearLayoutWithContextMenu extends LinearLayout implements ViewWithContextMenu {
public LinearLayoutWithContextMenu(Context context) {
super(context);
}
public LinearLayoutWithContextMenu(Context context, AttributeSet attrs) {
super(context, attrs);
}
private ContextMenuHandler handler;
@Override
public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler) {
this.handler = handler;
setOnCreateContextMenuListener(fragment);
}
@Override
public ContextMenuHandler getContextMenuHandler() {
return handler;
}
}
और अंत में, हमें संदर्भ मेनू कॉल को इंटरसेप्ट करने के लिए फ़्रैगमेंट क्लास की आवश्यकता होती है और उन्हें उपयुक्त हैंडलर पर पुनर्निर्देशित किया जाता है।
public class FragmentWithContextMenu extends Fragment {
ContextMenuHandler handler = null;
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
handler = null;
if (view instanceof ViewWithContextMenu) {
handler = ((ViewWithContextMenu)view).getContextMenuHandler();
if (handler != null) handler.onCreateContextMenu(menu, view, menuInfo);
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (handler != null) {
if (handler.onContextItemSelected(item)) return true;
}
return super.onContextItemSelected(item);
}
}
इस सब के साथ, अंतिम कार्यान्वयन बहुत सरल है। मुख्य अंश को FragmentWithContextMenu को उप-वर्ग करना है। यह मुख्य रूप से मुख्य RecylerWindow सेट करता है और खुद को एडेप्टर उपवर्ग में भेजता है। एडेप्टर उपवर्ग जैसा दिखता है
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private final FragmentWithContextMenu fragment;
Adapter(FragmentWithContextMenu fragment) {
this.fragment = fragment;
}
@Override
public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context)
.inflate(R.layout.child_view, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final Adapter.ViewHolder holder, int position) {
// Logic needed to bind holder to specific position
// ......
}
@Override
public int getItemCount() {
// Logic to return current item count
// ....
}
public class ViewHolder extends RecyclerView.ViewHolder implements ContextMenuHandler {
ViewHolder(View view) {
super(view);
((ViewWithContextMenu)view).setContextMenuHandler(fragment, this);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Do stuff to handle simple clicks on child views
// .......
}
});
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
// Logic to set up context menu goes here
// ....
}
@Override
public boolean onContextItemSelected(MenuItem item) {
// Logic to handle context menu item selections goes here
// ....
return true;
}
}
}
यह इसके बारे में। यह सब काम करता नजर आ रहा है। इसने सभी उपयोगिता वर्गों को एक अलग संदर्भों के पैकेज में रखा, ताकि मैं उन कक्षाओं को नाम दे सकूं जो उन कक्षाओं से मेल खाते थे, जो उपवर्ग हैं, लेकिन मुझे लगा कि यह अधिक भ्रमित करने वाला होगा।
ठीक है, @ Flexo के उत्तर के आधार पर, मैं ऑर्डर देने के लिए mPosition लगाऊंगा ...
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);
}
}
फिर onContextItemSelected में मैं उपयोग करता हूं
item.getOrder()
और सभी काम ठीक हैं मुझे आसानी से सरणी की स्थिति मिलती है