ViewHolderにClickListener実装させろ (http://stackoverflow.com/a/24933117) というのを見たけど
1要素のクリックなら1つのOnClickListenerで処理できるんじゃないの?というアプローチ。
RecyclerViewとRecyclerView.Adapterの結合
RecyclerView.Adapterには、以下のコールバックメソッドがあります。
onAttachedToRecyclerView(RecyclerView)
onDetachedFromRecyclerView(RecyclerView)
これらのコールバックによって、AdapterはどのRecyclerViewにattachされたのかがわかります。
RecyclerViewからpositionを取得する
RecyclerViewには、getChildAdapterPosition(view)というメソッドがあります。
このメソッドにViewを渡すと、そのViewのAdapter上のpositionが取得できます。
実装
View.OnClickListenerを1つ実装し、onCreateViewHolder()で、クリック可能にするすべてのアイテムViewにセットします。
処理的には、独自のリスナーを定義して、それにコールバックする処理を書けばいいです。
View.OnClickListenerのonClick()はクリックされたViewをくれるので、getChildAdapterPosition()と組み合わせることで要素の位置がわかります。
例
public class CustomRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener {
private final List<Item> mList = new ArrayList<>();
private RecyclerView mRecycler;
private OnItemClickListener mListener;
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecycler= recyclerView;
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
mRecycler = null;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = mInflater.inflate();
view.setOnClickListener(this);
RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(view);
return holder;
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
@Override
public void onClick(View view) {
if (mRecycler == null) {
return;
}
if (mListener != null) {
int position = mRecycler.getChildAdapterPosition(view);
Item item = mList.get(position);
mListener.onItemClick(this, position, item);
}
}
public static interface OnItemClickListener {
public void onItemClick(CustomRecyclerAdapter adapter, int position, Item item);
}
}
ちなみに、この実装では要素中の部分的なViewのクリックには対応できないです。
その場合は、素直にViewHolderにListenerを実装させましょう。
僕は、ViewHolderにAdapterを持たせて、ViewHolderからAdapterに一度コールバックしています。
public class CustomRecyclerAdapter extends RecyclerView.Adapter<Holder> {
// …
private void onButtonClick(int position) {
// アイテムのボタンクリック
}
static class Holder extends RecyclerView.ViewHolder implements OnClickListener {
private CustomRecyclerAdapter mAdapter;
public Holder(View itemView, CustomRecyclerAdapter adapter) {
super(itemView);
mAdapter = adapter;
itemView.findViewById(R.id.button).setOnClickListener(this);
}
public void onClick(View view) {
mAdapter.onButtonClick(getAdapterPosition());
}
}
実際はHolderにOnClickListener実装させるのではなく、ButterKnifeでbindしたほうがいいです。