Cách tạo menu ngữ cảnh cho RecyclerView


97

Làm cách nào để triển khai menu ngữ cảnh cho RecyclerView?Rõ ràng gọi registerForContextMenu(recyclerView)không hoạt động. Tôi đang gọi nó từ một mảnh vỡ. Có ai đã thành công khi thực hiện điều này?


Tôi ở trên cùng một con thuyền. Cố gắng ListView khác nhau appraoches với AdapterContextMenuInfo - nhưng không thể có được info.position
RoundSparrow hilltx

Tôi nghĩ rằng ngày của menu ngữ cảnh đã qua.
Binoy Babu

4
Này - tôi đã hiểu rồi;) tham khảo: stackoverflow.com/questions/2321332/… - ViewHolder đối với tôi là trình nghe onClick - tôi cũng đã đặt nó thành OnCreateContextMenuListener. Chìa khóa cho tất cả điều này là tôi nhận ra rằng chỉ có thể mở MỘT Menu tại một thời điểm - vì vậy bộ điều hợp chỉ cần một int được cho biết đó là mục danh sách RecyclerView cuối cùng đã nhấp vào menu ... sau đó Fragment / Activity có thể hỏi bộ điều hợp khi nó nhận được lần nhấp vào mục menu thực tế.
RoundSparrow hilltx

Câu trả lời:


92

Bạn không thể trực tiếp triển khai các phương pháp này như onClickListener , OnContextMenuListener , v.v. vì RecycleView mở rộng android.view.ViewGroup . Vì vậy, chúng tôi không thể trực tiếp sử dụng phương pháp này. Chúng ta có thể triển khai các phương thức này trong lớp bộ điều hợp ViewHolder . Chúng ta có thể sử dụng menu ngữ cảnh trong RecycleView như sau:

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


    }

Bây giờ chúng ta làm theo quy trình tương tự trong khi triển khai menu ngữ cảnh.

@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"); 

}

Nếu bạn gặp bất kỳ khó khăn nào, hãy hỏi trong bình luận.


7
Ok, và sau đó chúng tôi triển khai mức onContextItemSelectedhoạt động / phân mảnh. getTitlehoạt động, getItemIdhoạt động, nhưng getMenuInfophân phối rỗng. Vì vậy, làm thế nào để có được ahold của ViewHolder?
Michael Schmidt

@MichaelSchmidt bạn có thể cho tôi xem mã của bạn nơi bạn triển khai thông tin menu Ngữ cảnh không.
Prabhakar

7
Sau khi thử nghiệm một chút, tôi cũng không thể làm cho điều này hoạt động, getMenuInfo()trả về null in onContextItemSelected(). Có thể những người đã làm cho nó hoạt động tình cờ có một onCreateContextMenu()phương pháp trong một cái nhìn để nâng cao hơn nữa hệ thống phân cấp ( RecyclerViewhoặc Fragment)? Điều đó có thể hoạt động nhưng sau đó đưa chúng ta đến các câu trả lời khác cho câu hỏi này.
NeilS

3
Prabhakbar bạn không đề cập đến làm thế nào để có được mục đã nhấp cũng như không xem?
Benjamin Stürmer

6
Bạn có thể sử dụng menu.add(this.getAdapterPosition(), v.getId(), 0, "Call");và sau đó trong thử nghiệm phương pháp gọi lại của bạn cho item.getGroupId()để có được những vị trí
JacobPariseau

99

Cảm ơn vì thông tin và nhận xét. Tôi đã có thể đạt được ContextMenucho các mục trong Recyclerview.

Đây là những gì tôi đã làm

trong onViewCreatedphương thức của Fragment hoặc onCreatephương thức của Activity :

registerForContextMenu(mRecyclerView);

Sau đó, trong Bộ điều hợp thêm

private int position;

public int getPosition() {
    return position;
}

public void setPosition(int position) {
    this.position = position;
}

làm cho ViewHolderlớp thực hiệnOnCreateContextMenuListener

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

onBindViewHolderthêm phương thức OnLongClickListenervào hold.itemView để nắm bắt vị trí trước khi tải menu ngữ cảnh:

holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        setPosition(holder.getPosition());
        return false;
    }
});

Sau đó, onViewRecycledxóa Trình nghe để không có vấn đề tham chiếu. (có thể không bắt buộc).

@Override
public void onViewRecycled(ViewHolder holder) {
    holder.itemView.setOnLongClickListener(null);
    super.onViewRecycled(holder);
}

Cuối cùng trong Fragment / Activity ghi đè onContextItemSelectednhư sau:

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

1
position = ((BackupRestoreListAdapter) getAdapter ()). getPosition (); -> gặp lỗi: Phương thức getAdapter () không được xác định cho kiểu ..., bạn có thể chỉ cho phương thức getAdapter được không
nguoixanh

1
Đề xuất tuyệt vời, cảm ơn. Nhỏ: viewHolder.getPosition () không được dùng nữa. Lời khuyên của bạn để cải thiện là gì?
tm1701

10
sử dụng viewHolder.getAdapterPosition () thay vì getPosition ()
Sagar Chavada

2
Đối với những người gặp lỗi getAdapter (), tôi đã giải quyết nó bằng cách lưu một tham chiếu vào RecyclerView của mình và sau đó sử dụng nó như: ((BackupRestoreListAdapter) ReclerView.getAdapter ()). GetPosition ();
Kevin Amorim

1
Và chính xác thì R.id.ctx_menu_remove_backup ở đâu?
akubi

29

Câu trả lời hiện tại là không chính xác. Đây là một triển khai hoạt động:

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

Trong Phân đoạn (hoặc Hoạt động) của bạn:

@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
}

Và cuối cùng, trong ViewHolder của bạn:

class MyViewHolder extends RecyclerView.View.ViewHolder {
    ...
    private void onLongClick() {
        itemView.showContextMenu();
    }
}

Vui lòng thêm hàm tạo RecyclerView mà bạn phải triển khai trên ContextMenuRecyclerView của bạn. Và nó cũng getChildPosition()không được dùng nữa. Tôi đã sử dụng getChildAdapterPosition()thay thế.
Juan José Melero Gómez

1
Lưu ý: Xin lỗi, tôi quên thêm: getChildPosition()không được dùng nữa trong com.android.support:recyclerview-v7:22.0.0.
Juan José Melero Gómez

1
đây không phải là làm việc. bạn không thể truy cập getView (). showContextMenu () từ RecyclerView.View.ViewHolder.
Mulgard

4
Điều này làm việc cho tôi. Nhưng không cần phải có onLongClick () trong MyViewHolder, chỉ cần đặt itemView.setLongClickable (true) trong constructor, menu ngữ cảnh sẽ xuất hiện khi OnLongClickListener chưa được đăng ký.
alder,

2
Cũng quan trọng: trong khi mở rộng RecyclerView thành ContextMenuRecyclerView, đừng quên THÊM CÁC CÔNG TÁC HƯỚNG DẪN do IDE đề xuất. Cụ thể, nếu bạn không triển khai hàm tạo hai đối số lấy Context và AttributeSet, thì Android sẽ không thể tăng cường bố cục XML của bạn.
lidkxx

24

Hãy thử điều này cho một Viewmục trong 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;
                }
            });
        }
    });

Bạn có thể sử dụng nó với cài đặt dữ liệu cho một ViewHoldermục


Chính xác những gì tôi cần cho menu ngữ cảnh trên chế độ xem hình ảnh bên trong chế độ xem tái chế
Themos 12/1017

2
Đối với bất kỳ ai đang nhìn vào điều này ngay bây giờ, điều này chỉ hoạt động trên API 23 trở lên.
SWoo

16

Câu trả lời của Prabhakar là đúng, nhưng anh ta không giải thích cách lấy dữ liệu, liên quan đến mục được nhấn, khi một mục menu ngữ cảnh được chọn. Chúng ta có thể sử dụng onContextItemSelectedcallback, nhưng ContextMenuInfokhông khả dụng ( null) trong trường hợp này (nếu getContextMenuInfo()phương thức không được ghi đè cho dạng xem được nhấn). Vì vậy, giải pháp đơn giản nhất là thêm OnMenuItemClickListenertrực tiếp vào 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;
        }
    };
}

1
Giải thích rõ ràng, đoạn mã của bạn làm gì và như thế nào. Chỉ một mã đã sao chép là không đủ, ngay cả khi nó đáng giá.
peterh - Phục hồi Monica 16/10/15

Điều này dường như là một thỏa hiệp hợp lý nếu bạn không muốn tạo các lớp con tùy chỉnh RecyclerViewchỉ để ghi đè getContextMenuInfo, v.v., ngay cả khi nó không hoàn toàn hiệu quả bằng việc để phân đoạn / hoạt động xử lý các nhấp chuột. Người nghe sẽ có quyền truy cập vào dữ liệu trong trình lưu trữ, vì vậy bạn không cần vị trí. Và về mặt lý thuyết, bạn vẫn có thể lưu vào bộ nhớ cache vị trí khi ràng buộc trong bộ điều hợp của mình và sử dụng ủy quyền để gọi ra chủ sở hữu của bạn nếu bạn phải, mặc dù việc sử dụng Contexttừ một trong các chế độ xem bị ràng buộc đôi khi có thể là đủ.
qix

10

Câu trả lời của @ Renaud phù hợp với tôi nhưng trước tiên yêu cầu sửa một số mã. Nó giống như anh ấy đã đăng các đoạn mã từ một số lần lặp lại khác nhau của mã của mình. Những thay đổi cần được thực hiện là:

  • RecyclerContextMenuInfoRecyclerViewContextMenuInfolà cùng một lớp. Chọn một cái tên và gắn bó với nó.
  • Các ViewHolderphải thực hiện View.OnLongClickListener, và ghi nhớ để gọi setOnLongClickListener()vào mục trong constructor.
  • onLongClick()người nghe, getView().showContextMenu()là hoàn toàn sai lầm. Bạn phải gọi showContextMenuForChild()trong của bạn ContextMenuRecyclerView, nếu không ContextMenuInfobạn nhận được onCreateContextMenu()onContextItemSelected()sẽ vô hiệu.

Mã đã chỉnh sửa của tôi bên dưới:

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

Trong phân đoạn của bạn:

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

Trong ViewHolder của bạn:

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

Ngoài ra, hãy đảm bảo rằng bạn thay thế RecyclerViewbằng ContextMenuRecyclerViewtrong bố cục của mình!


1
Cảm ơn @ josh2112 đã chỉ cho tôi lỗi chính tả, tôi vừa sửa chúng - NHƯNG về điểm cuối cùng của bạn, bạn có thể thay thế recyclerView.showContextMenuForChild(itemView);bằng itemView.showContextMenu().
Renaud Cerrato

1
Cũng quan trọng: trong khi mở rộng RecyclerView thành ContextMenuRecyclerView, đừng quên THÊM CÁC CÔNG TÁC HƯỚNG DẪN do IDE đề xuất. Cụ thể, nếu bạn không triển khai hàm tạo hai đối số lấy Context và AttributeSet, thì Android sẽ không thể tăng cường bố cục XML của bạn.
lidkxx

5

Đây là một cách rõ ràng để sử dụng ngữ cảnh menu trên các mục RecyclerView

Đầu tiên, bạn cần một vị trí mục

Trong lớp Bộ điều hợp:

 /**
 * Custom on long click item listener.
 */
onLongItemClickListener mOnLongItemClickListener;

public void setOnLongItemClickListener(onLongItemClickListener onLongItemClickListener) {
    mOnLongItemClickListener = onLongItemClickListener;
}

public interface onLongItemClickListener {
    void ItemLongClicked(View v, int position);
}

Trong onBindViewHolderhook trình nghe tùy chỉnh:

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

Trong MainActivity (Hoạt động / Phân mảnh), hãy tạo một trường:

private int mCurrentItemPosition;

Trong đối tượng Bộ điều hợp của bạn, hãy đặt trình nghe tùy chỉnh:

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

Bây giờ bạn có một vị trí tuyệt vời cho bất kỳ mục nào bạn đã nhấp vào nó từ lâu 😋

Thứ hai, tạo menu của bạn

Trong menu res -> Tạo một tệp chứa mục menu của bạn 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>

Trong MainActivity: Triển khai cả onCreateContextMenuonContextItemSelected:

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

Thứ ba, quay lại đối tượng Bộ điều hợp của bạn

  1. Đăng ký menu ngữ cảnh của bạn.
  2. hiển thị menu ngữ cảnh.

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

Hy vọng tôi không quên bất cứ điều gì 🤔

Thông tin thêm tại Tài liệu menu


Cảm ơn! Làm thế nào để chuyển dữ liệu vào menu ngữ cảnh? Ví dụ: id mặt hàng, văn bản mặt hàng, v.v.
CoolMind

4

Đây là một cách đơn giản hơn để làm điều đó với Kotlin đã phù hợp với tôi. Thách thức chính là tìm ra vị trí của mục được ấn. Bên trong bộ điều hợp của mình, bạn có thể đặt đoạn mã này và nó sẽ có thể nắm bắt vị trí của mục mà menu ngữ cảnh được hiển thị; đó là tất cả.

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

} 

2
Đây là cách tự nhiên nhất và có thể kiểm soát được
nima

3

Tôi đã kết hợp giải pháp của mình với giải pháp từ @Hardik Shah:

Trong hoạt động tôi có:

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

Trong Bộ điều hợp tôi có:

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

Trong phân đoạn tôi có:

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

2

Tôi có thể đến muộn bữa tiệc nhưng tôi có một giải pháp làm việc . Tôi đã đưa ra một ý chính cho nó.

Thêm trình đơn ngữ cảnh vào 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;
    }

}

1

Xin chào các bạn đã ra mắt một giải pháp thay thế phù hợp với tôi. Tôi chỉ cần đăng ký itemView của mình với registerContextMenu y là ViewHolder Constructor, cũng đặt onLongClikcListener cho cùng một View. Trong triển khai onLongClick (View v), tôi chỉ cần lấy vị trí đã nhấp bằng getLayoutPosition () và lưu trong một biến thể hiện (tôi đã tạo một lớp để đại diện cho dữ liệu này, giống như ContextMenuInfo dự kiến ​​sẽ hoạt động), nhưng quan trọng hơn là làm chắc chắn rằng bạn trả về false trong phương thức này. Tất cả những gì bạn phải làm bây giờ là ở bạn trên onContextItemSelected (mục MenuItem), đọc dữ liệu mà bạn lưu trữ trong biến thể hiện của mình và nếu nó hợp lệ, bạn tiến hành các hành động của mình. Đây là một đoạn mã.

  public MyViewHolder(View itemView){
super(itemView);
registerForContextMenu(itemView);
itemView.setOnLongClickListener(this);
}

Tôi làm cho ViewHolder triển khai OnLongClickListener, nhưng bạn có thể thực hiện theo bất kỳ cách nào bạn muốn.

@Override
public boolean onLongClick(View v){
    mCurrentLongItem = new ListItemInfo(v.getId(), getLayoutPosition());
    return false; // REMEMBER TO RETURN FALSE.
  }

Bạn cũng có thể đặt điều này trong bộ điều hợp hoặc cho một Chế độ xem khác mà bạn có trong ViewHolder (tức là một TextView). Điều quan trọng là triển khai 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);
}

Phần tốt nhất là bạn vẫn có thể xử lý sự kiện LongClick trả về true trong trường hợp bạn muốn và conextMenu sẽ không hiển thị.

Phương thức này hoạt động vì registerForContextView làm cho View LongClickable và khi đến thời điểm xử lý ContextMenu, hệ thống sẽ gọi performanceLongClick, phương thức này đầu tiên sẽ gọi một triển khai onLongClick và nếu nó trả về false, thì nó sẽ gọi showContextMenu.


1

Tôi đã sử dụng giải pháp này đôi khi và nó hoạt động khá tốt cho tôi.

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

Bây giờ trong phân đoạn hoặc Hoạt động của bạn, hãy triển khai các phương pháp sau.

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

Cuối cùng Đăng ký bối cảnhMenu trên chế độ xem lại

   //for showing a popup on LongClick of items in recycler.
    registerForContextMenu(recyclerView);

Cần làm việc!


1

Đây là cách bạn có thể triển khai menu ngữ cảnh cho RecyclerView và lấy vị trí của mục, mục menu ngữ cảnh đã được chọn:

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

}


1

Một giải pháp cho những ai muốn lấy id item khi gọi ContextMenu.

Nếu bạn có RecyclerViewvới các mục như thế này (chứa có thể nhấp ImageView):

danh sách

thì bạn sẽ nhận được các cuộc gọi lại từ onClickListener.

Bộ chuyển đổi

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

Miếng

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

Cảnh báo!

Nếu bạn sử dụng ViewPagerdựa trên một phân đoạn (tất cả các trang là danh sách tương tự), bạn sẽ gặp phải vấn đề. Khi bạn ghi đè onContextItemSelectedđể hiểu mục menu nào đã được chọn, bạn sẽ nhận được id mục danh sách từ trang đầu tiên! Để khắc phục sự cố này, hãy xem Phân đoạn sai trong ViewPager nhận lệnh gọi onContextItemSelected .


0

Tôi đã gặp khó khăn về vấn đề này vì Android không xử lý điều này tốt cho tôi trong RecyclerView, vốn đang hoạt động rất tốt cho ListView.

Khó khăn nhất là phần ContextMenuInfo được nhúng bên trong một Chế độ xem, mà bạn không thể dễ dàng đính kèm ngoài việc ghi đè Chế độ xem.

Vì vậy, bạn sẽ cần một trình bao bọc giúp bạn cung cấp thông tin vị trí cho Hoạt động.

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

}

Sau đó, trong RecyclerAdapter của bạn, khi bạn tạo ViewHolders, bạn cần đặt Wrapper làm chế độ xem gốc và đăng ký contextMenu trên mỗi chế độ xem.

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

}

Và cuối cùng, trong Hoạt động của bạn, bạn sẽ có thể làm những gì bạn thường làm:

@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

0

Cách tốt nhất là sử dụng menu Ngữ cảnh với chế độ xem trình tái chế là nếu bạn tạo chế độ xem trình tái chế tùy chỉnh và ghi đè getContextMenuInfo()phương thức và trả về bản sao của đối tượng thông tin menu Ngữ cảnh để bạn có thể tìm nạp các vị trí khi nó được tạo và khi menu được nhấp:

@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
    return mContextMenuInfo;
}

Hãy xem ý chính mà tôi đã tạo:

https://gist.github.com/resengupta/2b2e26c949b28f8973e5


0

Mở rộng một số câu trả lời ở trên một chút, nếu bạn muốn tránh xác định thủ công menu trong mã của mình trong Bộ điều hợp / ViewHolder thì bạn có thể sử dụng PopupMenu và tăng các tùy chọn menu từ tệp tài nguyên menu.xml tiêu chuẩn.

Ví dụ bên dưới cho thấy điều này bao gồm khả năng chuyển vào một trình lắng nghe mà bạn có thể triển khai trong Phân đoạn / Hoạt động của mình để phản hồi các lần nhấp vào menu ngữ cảnh.

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

Ý chính đầy đủ tại đây https://gist.github.com/brettwold/45039b7f02ce752ae0d32522a8e2ad9c


0

Bạn có thể chuyển OnCreateContextMenuListener vào ViewHolder trên bind. Trình nghe này có thể tạo menu tùy chỉnh cho từng mục dữ liệu. Chỉ cần thêm setOnCreateContextMenuListener trong ViewHolder của bạn và gọi nó trong quá trình ràng buộc.

     public static class ItemViewHolder extends RecyclerView.ViewHolder
     {


        public ItemViewHolder(View itemView) {
            super(itemView);


        }
        void setOnCreateContextMenuListener(View.OnCreateContextMenuListener listener) {
            itemView.setOnCreateContextMenuListener(listener);
        }

}

Trong bộ chuyển đổi:

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

                        }
                    }

                });
     }

0

Trong trường hợp của tôi, tôi phải sử dụng dữ liệu từ phân đoạn của mình trong onContextItemSelected()phương thức. Giải pháp mà tôi đã thực hiện là chuyển một phiên bản của phân đoạn vào bộ điều hợp của tôi và đăng ký mục xem trong trình giữ chế độ xem:

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

Sau đó, onCreateContextMenu()bạn có thể lưu chỉ mục vào một biến cục bộ:

selectedViewIndex = (int)v.getTag();

và lấy nó trong onContextItemSelected()


0

Lần đầu tiên tôi gặp sự cố này với các bộ điều hợp thông thường, tôi đã kết thúc việc tạo lớp con Chế độ xem tùy chỉnh của riêng mình và lưu trữ những thứ tôi cần trong đó. Tôi thực sự không thích giải pháp đó và đã dành rất nhiều thời gian để xem xét những ý tưởng tuyệt vời mà mọi người đã đề xuất, và quyết định rằng tôi không thích chúng hơn nữa. Vì vậy, tôi đã sắp xếp mọi thứ lại với nhau, lắc nó một lúc và cho ra một thứ mới mà tôi thích.

Chúng tôi bắt đầu với một vài lớp tiện ích. ContextMenuHandler là một giao diện cho bất kỳ đối tượng nào sẽ xử lý menu ngữ cảnh. Trong thực tế, đây sẽ là một lớp con của ViewHolder, nhưng về lý thuyết, nó có thể là bất cứ thứ gì

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

Tiếp theo là một Giao diện phải được thực hiện bởi bất kỳ Chế độ xem nào sẽ được sử dụng làm con ngay lập tức của Chế độ xem tái chế.

public interface ViewWithContextMenu {
  public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler);

  public ContextMenuHandler getContextMenuHandler();
}

Tiếp theo, bất kỳ chế độ xem nào sẽ tạo menu ngữ cảnh dưới dạng phần tử con của RecylcerView phải triển khai ViewWIthContextMenu. Trong trường hợp của tôi, tôi chỉ cần một lớp con của 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;
  }
}

Và cuối cùng, chúng ta cần một lớp Fragment được cải tiến để chặn các lệnh gọi menu ngữ cảnh và chuyển hướng chúng đến trình xử lý thích hợp.

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

Với tất cả những điều này, việc thực hiện cuối cùng khá đơn giản. Phân đoạn chính phải phân lớp FragmentWithContextMenu. Nó thiết lập RecylerWindow chính bình thường và tự chuyển sang lớp con Bộ điều hợp. Lớp con Bộ điều hợp trông giống như

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

Đó là về nó. Tất cả dường như đang hoạt động. Nó đặt tất cả các lớp tiện ích trong một gói ngữ cảnh riêng biệt để tôi có thể đặt tên các lớp phù hợp với các lớp có phân lớp, nhưng tôi nghĩ sẽ khó hiểu hơn.


-1

Được rồi, dựa trên câu trả lời của @ Flexo, tôi sẽ đặt mPosition để đặt hàng ...

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

thì trong onContextItemSelected tôi sử dụng

item.getOrder() 

Và tất cả đều hoạt động tốt, tôi có được vị trí của mảng một cách dễ dàng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.