RecyclerViewで要素を長押しして、要素毎に内容の変わるコンテキストメニューを表示する方法の記事が見当たらなかったのでメモしてみます!
実装方法
コンテキストメニューの表示
Activity or Fragmentに
View.OnCreateContextMenuListener
をimplementsします。
public class SampleFragment extends Fragment
implements View.OnCreateContextMenuListener {
他にもViewHolderにimplementsするパターンもありますが、
コンテキストメニューを要素毎に内容を出し分けしたくて、都合のよかったFragmentにimplementsしました。
次に、RecyclerViewを生成をしているonCreatedViewメソッドで
RecyclerView rv = view.findViewById(R.id.recyclerView);
// Adapter等のアタッチは省略します
registerForContextMenu(rv); // 追記
を追記します。
registerForContextMenu
はView.OnCreateContextMenuListenerをimplementsすることで呼び出せるようになります。
この記述でコンテキストメニューを認識させることができます。
続いて、FragmentにonCreateContextMenu
を実装します。
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
// 長押しされたメッセージ位置を取得し、
// RecyclerViewで表示させているListのindexとして扱い、
// ユーザーIDを取得してメニューの出し分けを実現
if (list.get(adapter.getPosition()).getUserId() == loginUserId) {
menu.add(Menu.NONE, 1, Menu.NONE, "コピー");
menu.add(Menu.NONE, 2, Menu.NONE, "編集");
menu.add(Menu.NONE, 3, Menu.NONE, "削除");
} else {
menu.add(Menu.NONE, 1, Menu.NONE, "コピー");
}
}
ContextMenuオブジェクトに追加したい内容をaddする形で簡単に項目を追加できます。
addメソッドの第二引数に数値をセットしていますが、これは押された際のリスナーのハンドリングで使用します。
参考程度ですが、Adapterに以下の要領でgetPosition()
メソッドを用意して、長押しされた要素の位置を取得できるようにしています。
@Override
public void onBindViewHolder(final ChatViewHolder holder, int position) {
// 省略
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
setPosition(holder.getPosition());
return false;
}
});
}
// 長押しされた要素の位置を取得する
public int getPosition() {
return position;
}
// 長押しされた要素の位置をセットする
public void setPosition(int position) {
this.position = position;
}
ここまでの実装でコンテキストメニューは表示できます。
コンテキストメニューのイベントリスナー
以下のように、onContextItemSelected
を実装し、中でswitch文を用いてハンドリングします。
MenuItem.getItemId()で先ほど登録した各要素の判別用の数値が取得できますので、
switch文で振り分ける感じですね。
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 1:
// TODO メッセージをクリップボードにコピー
return true;
case 2:
// TODO メッセージを編集
return true;
case 3:
// TODO メッセージを削除
return true;
default:
return false;
}
}
以上です。
どなたかの参考になりましたら幸いです!!