Handle Click Events of Multiple Buttons Inside a RecyclerView
Handling multiple click events of multiple buttons placed inside CardView / RecyclerView from Activity instead of from Adapter
Introduction
There are general scenarios where we need to have the button click events be handled inside the Activity instead of an Adapter.
Background
A simple method adding a Listener
Interface which is implemented in the Adapter.
Using the Code
Here, using a RecyclerView
which holds a CardView
and multiple inside CardView
. A simple scenario which is picked to explain this is, filtering RecyclerView
with List
of Trains
to be booked in CardViews
. Further, the User
shall click on Days
button (days the train runs) and the Class
button (shows another View
as per the Class
selection). For simplicity and to stick to the topic, only relevant code snippets have been included.
public class TrainBwStnAdapater extends RecyclerView.Adapter<TrainBwStnAdapater.TrainStnViewHolder> {
//region variables
private Context mContext;
private List<TrainDetail> mTrainDetails;
public DetailsAdapterListener onClickListener;
//endregion
//region viewholder class
public class TrainStnViewHolder extends RecyclerView.ViewHolder {
//using ButterKnife for Binding
//other fields removed for simplicity
@BindView(R.id.bw_trnNo)
TextView mTrainNo;
@BindView(R.id.class_btn)
AppCompatButton mClassBtn;
@BindView(R.id.days_btn)
AppCompatButton mDaysBtn;
public TrainStnViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
mClassBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickListener.classOnClick(v, getAdapterPosition());
}
});
mDaysBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickListener.daysOnClick(v, getAdapterPosition());
}
});
}
}
//endregion
//region constructor
public TrainBwStnAdapater(Context context, List<TrainDetail> mTrainDetails,
DetailsAdapterListener listener) {
this.mContext = context;
this.mTrainDetails = mTrainDetails;
this.onClickListener = listener;
}
//endregion
//region overrides
@Override
public TrainBwStnAdapater.TrainStnViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.train_bw_stn_card, parent, false);
return new TrainStnViewHolder(itemView);
}
@Override
public void onBindViewHolder(TrainBwStnAdapater.TrainStnViewHolder holder, final int position) {
TrainDetail trainDetail = mTrainDetails.get(position);
holder.mTrainNo.setText(String.valueOf(trainDetail.getNumber()));
//other fields removed for simplicity
}
@Override
public int getItemCount() {
return mTrainDetails.size();
}
//endregion
//region Interface Details listener
public interface DetailsAdapterListener {
void classOnClick(View v, int position);
void daysOnClick(View v, int position);
}
//endregion
}
From the above code snippet, there is an Interface which is supposed to act as the Listener
attached with the ClickListener
. Also, see the constructor where it takes Listener
as one of the parameters.
Calling part or the Activity
code snippet is as below:
mTrainDetails = getTrain();
mAdapter = new TrainBwStnAdapater(getBaseContext(),
mTrainDetails, new TrainBwStnAdapater.DetailsAdapterListener() {
@Override
public void classOnClick(View v, int position) {
showClass(mTrainDetails, position);// do something or navigate to detailed classes
}
@Override
public void daysOnClick(View v, int position) {
showDays(mTrainDetails, position);// do something or navigate to running days
}
});
recyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
Hope this was kept as simple as possible and was helpful in such common scenarios.
History
- 12th February, 2018: Initial version