How to add a button at the end of RecyclerView?
I came across this problem and found this answer. The current selected answer is correct but it is missing some details. Here is the full implementation,
Add this method to your adapter
@Override
public int getItemViewType(int position) {
return (position == myItems.size()) ? R.layout.button : R.layout.item;
}
It will check if the current position is past the last item in your list, if it is then it will return the button layout value to this method,
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView;
if(viewType == R.layout.item){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
}
else {
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.button, parent, false);
}
return new MyViewHolder(itemView);
}
The above method checks if the passed viewType
is the item
layout or the button
layout and then inflates the view occordingly and sends the inflated view to this method,
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if(position == myItems.size()) {
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context, "Button Clicked", Toast.LENGTH_LONG).show();
}
});
}
else {
final String name = myItems.get(position);
holder.title.setText(name);
}
}
This checks if we are past the last item
in the list and if we are then it sets the onClick
method to our button. Otherwise it creates an item
like normal.
We also need to change the getItemCount
method to this
@Override
public int getItemCount() {
return myItems.size() + 1;
}
Since we are going through all the items
and then adding a button
at the end, the + 1
is our button.
Then lastly we need to add our view to the myViewHolder
class
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public Button button;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
button = (Button) view.findViewById(R.id.bottom_button);
}
}
I hope this helps!
One way to do it would be to make your footer view a "ViewType" of your adapter. In order to do that, overrides getItemViewType to return a different value for your last item.
@Override
public int getItemViewType(int position) {
return (position == mData.size()) ? VIEW_TYPE_FOOTER : VIEW_TYPE_CELL;
}
Then in the onCreateViewHolder, handle the different viewType.
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_CELL) {
//Create viewholder for your default cell
}
else {
//Create viewholder for your footer view
}
}
Don't forget to update the value return by getCount() by adding 1, and to distinguish the 2 types of ViewHolder in OnBindViewHolder (with instanceof for example).
This is what I am using in kotlin. Hope it helps somebody.
class ThumbnailsAdapter(
private val mContext: Context,
private val list: ArrayList<Image>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
R.layout.z_thumbnail -> {
val view = LayoutInflater.from(mContext)
.inflate(R.layout.z_thumbnail, parent, false)
ThumbnailViewHolder(view)
}
R.layout.z_thumbanail_add -> {
val view = LayoutInflater.from(mContext)
.inflate(R.layout.z_thumbanail_add, parent, false)
PlaceholderViewHolder(view)
}
else -> throw IllegalArgumentException("unknown view type $viewType")
}
}
override fun getItemCount(): Int {
return list.size + 1
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
R.layout.z_thumbnail -> (holder as ThumbnailViewHolder).bind(list[position].path)
R.layout.z_thumbanail_add -> (holder as PlaceholderViewHolder).bind()
}
}
override fun getItemViewType(position: Int): Int {
return when (position) {
list.size -> R.layout.z_thumbanail_add
else -> R.layout.z_thumbnail
}
}
inner class ThumbnailViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val imageView = itemView.findViewById<ImageView>(R.id.thumbnail)
fun bind(path: String) {
Glide.with(mContext).load(path).into(imageView)
}
}
inner class PlaceholderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val btn = itemView.findViewById<ImageView>(R.id.add_images_btn)
fun bind() {
btn.setOnClickListener {
//Do your logic here for the button
}
}
}
}
There is a very simple way to that first you need to add +1 to size of the list
@Override
public int getItemCount() {
return badgesModels.size() + 1;
}
then check if the position of the list is grater than the size of the list do something. in my case:
if (position == badgesModels.size()) {
holder.imageViewBadege.setImageDrawable(getResources().getDrawable(R.drawable.plus));
holder.imageViewBadege.setBackgroundColor(getResources().getColor(R.color.bg_gray));
holder.textViewBadgeTitle.setText("Make Badge");
holder.imageViewBadege.setOnClickListener(v -> {
ListDialog.newInstanceChooseBadge().show(Objects.requireNonNull(getFragmentManager()),"makeBadge");
});
} else {
GlideApp.with(Objects.requireNonNull(getContext())).load(results.get(position).getImage_link()).placeholder(R.drawable.badge).into(holder.imageViewBadege);
holder.textViewBadgeTitle.setText(results.get(position).getTitle());
holder.imageViewBadege.setOnClickListener(v -> {
apiService.assginBadgesStudent(classId, studentId, results.get(position).getId());
dismiss();
Objects.requireNonNull(getTargetFragment()).onResume();
playFromAsset("sounds/ding.wav");
});
}