RecyclerView?
분명히 전화 registerForContextMenu(recyclerView)
가 작동하지 않는 상황에 맞는 메뉴를 구현하는 방법 . 나는 그것을 조각에서 부르고있다. 아무도 이것을 구현하는 데 성공 했습니까?
RecyclerView?
분명히 전화 registerForContextMenu(recyclerView)
가 작동하지 않는 상황에 맞는 메뉴를 구현하는 방법 . 나는 그것을 조각에서 부르고있다. 아무도 이것을 구현하는 데 성공 했습니까?
답변:
RecycleView는 android.view.ViewGroup을 확장 하므로 onClickListener , OnContextMenuListener 등과 같은 메서드를 직접 구현할 수 없습니다 . 따라서 우리는 이러한 방법을 직접 사용할 수 없습니다. 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
null을 제공합니다. 그래서, 어떻게 얻을 수 ViewHolder
있습니까?
getMenuInfo()
null을 반환합니다 onContextItemSelected()
. 아마도 그것을 작동시킨 사람들 onCreateContextMenu()
이 계층 구조보다 더 높은 뷰에 메소드 를 가지고있을 수 있습니까 ( RecyclerView
또는 Fragment
)? 작동 할 수 있지만이 질문에 대한 다른 답변으로 이동합니다.
menu.add(this.getAdapterPosition(), v.getId(), 0, "Call");
에 대한 귀하의 콜백 메소드 시험에서 다음과 item.getGroupId()
위치를 얻을 수
정보와 의견에 감사드립니다. ContextMenu
에서 항목 을 달성 할 수있었습니다 Recyclerview
.
내가 한 일은 다음과 같습니다.
Fragment의 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
컨텍스트 메뉴가로드되기 전에 위치를 캡처하기 위해 holder.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);
}
마지막으로 Fragment / Activity 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
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;
}
});
}
});
ViewHolder
항목 에 대한 설정 데이터와 함께 사용할 수 있습니다.
Prabhakar 대답 은 정확하지만 상황에 맞는 메뉴 항목을 선택할 때 누른 항목과 관련된 데이터를 얻는 방법을 설명하지 않았습니다. 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
바인딩 된 뷰 중 하나를 사용하는 것으로도 충분할 수 있습니다.
@Renaud의 대답은 나를 위해 일했지만 먼저 몇 가지 코드 수정이 필요했습니다. 그는 자신의 코드를 여러 번 반복하여 스 니펫을 게시 한 것과 같습니다. 변경해야 할 사항은 다음과 같습니다.
RecyclerContextMenuInfo
과 RecyclerViewContextMenuInfo
같은 클래스입니다. 이름을 정하고 그것에 충실하십시오.ViewHolder
구현해야 View.OnLongClickListener
하고, 전화를 기억 setOnLongClickListener()
생성자의 항목.onLongClick()
리스너, getView().showContextMenu()
완전히 잘못된 것입니다. 당신은 호출해야 showContextMenuForChild()
당신에 ContextMenuRecyclerView
그렇지 않으면, ContextMenuInfo
당신이 얻을 onCreateContextMenu()
및 onContextItemSelected()
null가됩니다.아래 수정 된 코드 :
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 (Activity / Fragment)에서 필드를 만듭니다.
private int mCurrentItemPosition;
Adapter 객체에서 사용자 정의 리스너를 설정합니다.
mAdapter.setOnLongItemClickListener(new FileAdapter.onLongItemClickListener() {
@Override
public void ItemLongClicked(View v, int position) {
mCurrentItemPosition = position;
}
});
이제 오랫동안 클릭 한 항목에 대한 맛있는 위치가 있습니다 😋
입술에서-> 메뉴
메뉴 항목을 포함하는 파일을 만듭니다 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>
MainActivity에서 :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();
}
});
아무것도 잊지 않길 바래 🤔
메뉴 문서 에서 더 많은 정보
나를 위해 일한 Kotlin으로 작업을 수행하는 더 간단한 방법이 있습니다. 가장 큰 도전은 눌린 항목의 위치를 파악하는 것입니다. 어댑터 내부에이 코드 조각을 배치하면 상황에 맞는 메뉴가 표시되는 항목의 위치를 캡처 할 수 있습니다. 그게 다야.
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
}
}
}
내 솔루션을 @Hardik Shah의 솔루션과 결합했습니다.
활동에서 나는 :
@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);
}
}
파티에 늦었을 수도 있지만 해결 방법이 있습니다. 있습니다. 나는 그것에 대한 요점을 만들었습니다.
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;
}
}
안녕하세요 여러분, 저에게 맞는 대안이 나왔습니다. 내 itemView를 registerContextMenu y ViewHolder 생성자에 등록하고 onLongClikcListener를 동일한 View로 설정합니다. onLongClick (View v) 구현에서는 getLayoutPosition ()을 사용하여 클릭 한 위치를 가져오고 인스턴스 변수에 저장합니다 (ContextMenuInfo가 작동 할 것으로 예상되는 것처럼이 데이터를 나타내는 클래스를 만들었습니다).하지만 더 중요한 것은 이 메서드에서 false 를 반환해야합니다 . 지금해야 할 일은 onContextItemSelected (MenuItem item)에서 인스턴스 변수에 저장 한 데이터를 읽고 유효하면 작업을 진행하는 것입니다. 여기에 스 니펫이 있습니다.
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에있는 다른보기 (예 : TextView)에서이를 설정할 수도 있습니다. 중요한 것은 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);
}
가장 좋은 점은 원하는 경우 true를 반환하는 LongClick 이벤트를 처리 할 수 있으며 conextMenu가 표시되지 않는다는 것입니다.
이 메서드는 registerForContextView가 View를 LongClickable로 만들고 ContextMenu를 처리 할 때 시스템이 performLongClick을 호출하여 먼저 onLongClick 구현을 호출하고 false를 반환하면 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에서 contextMenu에 등록하십시오.
//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;
}
}
}
전화 할 때 아이템 ID를 받고 싶은 분들을위한 솔루션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
선택한 메뉴 항목을 이해하기 위해 재정의 하면 첫 페이지에서 목록 항목 ID를 받게됩니다! 이 문제를 해결하려면 ViewPager의 잘못된 조각 이 onContextItemSelected 호출을받습니다 .
Android가 ListView에서 매우 잘 작동하는 RecyclerView에서 나를 위해 잘 처리하지 않기 때문에 나는 이것에 어려움을 겪고 있습니다.
가장 어려운 부분은 ContextMenuInfo 부분이 뷰에 포함되어 있다는 것입니다. 뷰를 재정의하는 것 외에는 쉽게 연결할 수 없습니다.
따라서 활동에 위치 정보를 전달하는 데 도움이되는 래퍼가 필요합니다.
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를 루트 뷰로 설정하고 각 뷰에 contextMenu를 등록해야합니다.
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;
}
내가 만든이 요점을 살펴보십시오.
Adaptor / ViewHolder의 코드에서 메뉴를 수동으로 정의하지 않으려면 위의 일부 답변을 확장하면 PopupMenu를 사용하고 표준 menu.xml 리소스 파일에서 메뉴 옵션을 확장 할 수 있습니다.
아래 예는 컨텍스트 메뉴 클릭에 응답하기 위해 Fragment / Activity에서 구현할 수있는 리스너를 전달하는 기능을 포함하여이를 보여줍니다.
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()
일반 어댑터에서 처음으로이 문제가 발생했을 때 사용자 정의 View 하위 클래스를 만들고 필요한 항목을 저장했습니다. 저는 그 솔루션이 정말 마음에 들지 않았고 사람들이 제안한 훌륭한 아이디어를 보는 데 많은 시간을 보냈으며 더 이상 좋아하지 않는다고 결정했습니다. 그래서 저는 모든 것을한데 모아 잠시 흔들고 제가 좋아하는 새로운 것을 나왔습니다.
몇 가지 유틸리티 클래스로 시작합니다. 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의 직계 자식으로 사용될 모든 View에 의해 구현되어야하는 인터페이스입니다.
public interface ViewWithContextMenu {
public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler);
public ContextMenuHandler getContextMenuHandler();
}
다음으로, RecylcerView의 자식으로 컨텍스트 메뉴를 만들 모든 뷰는 ViewWIthContextMenu를 구현해야합니다. 제 경우에는 LinearLayout의 하위 클래스 만 필요했습니다.
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;
}
}
마지막으로 상황에 맞는 메뉴 호출을 가로 채서 적절한 핸들러로 리디렉션하기 위해 강화 된 Fragment 클래스가 필요합니다.
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를 정상적으로 설정하고 Adapter 하위 클래스로 전달합니다. Adapter 하위 클래스는 다음과 같습니다.
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 I 사용
item.getOrder()
그리고 모두 잘 작동합니다. 배열의 위치를 쉽게 얻습니다.