Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a view dynamically to the item of the RecyclerView

Tags:

I want to add the extra TextView to the item of the RecyclerView.Adapter based on the ModalObject sent to the RecyclerView.Adapter

Example:

I had a modal object with isAddText variable. In onCreateViewHolder will create the Holder Object with sending the itemView as an parameter.

@Override public SolventViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {     View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.solvent_list, null);     SolventViewHolders rcv = new SolventViewHolders(layoutView);     return rcv; } 

SolventViewHolders.java

public SolventViewHolders(View itemView) {     super(itemView);     itemView.setOnClickListener(this);     textView = (TextView) itemView.findViewById(R.id.country_name);     imageView = (ImageView) itemView.findViewById(R.id.country_photo);     //  Now i need add a view to the itemView parent based on ModalObject isAddView property and how to do that.  } 
like image 551
user3607798 Avatar asked Sep 01 '15 13:09

user3607798


People also ask

What is a dynamic RecyclerView?

Dynamic RecyclerView With Non-Defined Data Structure (From Unknown CSV Data Structure) RecyclerView makes it easy to efficiently display large sets of data. You supply the data and define how each item looks, and the RecyclerView library dynamically creates the elements when they're needed.

What is Item view in RecyclerView?

A ViewHolder describes an item view and metadata about its place within the RecyclerView. RecyclerView. Adapter implementations should subclass ViewHolder and add fields for caching potentially expensive View. findViewById(int) results.

What does notifyDataSetChanged do in RecyclerView?

notifyDataSetChanged. Notify any registered observers that the data set has changed. There are two different classes of data change events, item changes and structural changes. Item changes are when a single item has its data updated but no positional changes have occurred.


1 Answers

The problem

Normally, you would need to execute itemView.addView(view, layoutParams) to add another view programatically to your layout, but thing with ViewHolders is, they will be reused by RecyclerView to bind different items from the adapter, so you can't do that or this new TextView you wish to add will appear when another item is bound to this viewHolder instance again.

I can think of a few ways you can achieve your goal:


1. Switch the View's visibility

The first way is to add this textView to your layout and have its visibility by GONE by default, and set it to VISIBLE when binding that one item you need this TextView for, such as:

@Override public void onBindViewHolder(AbstractViewHolder holder, int position) {     holder.extraTextView.setVisibility(View.GONE);     if(shouldShowExtraTextView) {         holder.extraTextView.setVisibility(View.VISIBLE);         holder.extraTextView.setText(/* your text */);     }     // proceed to bind item to holder } 

2. Implement different ViewHolders

The second way is more elegant, it involves creating different ViewHolder type. First you need to create int constants for the two types of view to be shown by RecyclerView. Place in your adapter the following code:

private static final int VIEW_ORDINARY = 0; private static final int VIEW_WITH_EXTRA_TEXT_VIEW = 1; 

Then implement the getItemViewType(int position) method of the adapter:

@Override public int getItemViewType(int position) {     if(position == /* position of item that needs extra text view */) {         return VIEW_WITH_EXTRA_TEXT_VIEW;     } else {         return VIEW_ORDINARY;     } } 

Next step is to create different Holder depending on returned type:

@Override public SolventViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {     if(viewType == VIEW_WITH_EXTRA_TEXT_VIEW) {         View itemView = LayoutInflater.from(parent.getContext())                                       .inflate(R.layout.solvent_list_with_extra_text_view, parent, false);         return new SolventViewHolderWithExtraTextView(itemView);     } else {         View itemView = LayoutInflater.from(parent.getContext())                                       .inflate(R.layout.solvent_list, parent, false);         return new SolventViewHolder(itemView);     } } 

Of course you need to define SolventViewHolderWithExtraTextView:

class SolventViewHolderWithExtraTextView extends SolventViewHolder {     TextView extraTextView;      public SolventViewHolderWithExtraTextView(View itemView) {         super(itemView);         this.extraTextView = (TextView) findViewById(R.id.extra_text_view);     } } 

And then in onBindViewHolder():

@Override public void onBindViewHolder(SolventViewHolder holder, int position) {     // you can use inheritance to handle binding logic or check the item view type again:     // bind ordinary view     if(getItemViewType(position)) {         // bind the extra textView         ((SolventViewHolderWithExtraTextView)holder).extraTextView.setText("I hope this works");     } } 

This way you have another type of ViewHolder for your items that need another TextView, and it will be reused within that category. It's a preferred way to do what you want to.


3. Add/remove View dynamically

Another answer (which is really ugly solution if you ask me) is to add and remove view dynamically, such as:

@Override public void onBindViewHolder(AbstractViewHolder holder, int position) {     if(shouldDisplayExtraTextView) {         if(!holder.displaysExtraTextView() {             holder.addExtraTextView();         }         holder.extraTextView.setText("This solution is really ugly");         } else {         if(holder.displaysExtraTextView() {             holder.removeExtraTextView();         }     } }  class SolventViewHolders extends RecyclerView.ViewHolder {     TextView extraTextView;     boolean viewAdded = false;      public SolventViewHolders(View itemView) {         super(itemView);         itemView.setOnClickListener(this);         textView = (TextView) itemView.findViewById(R.id.country_name);         imageView = (ImageView) itemView.findViewById(R.id.country_photo);          //  Now i need add a view to the itemView parent based on ModalObject isAddView property and how to do that.           extraTextView = new TextView(); }  public void addExtraTextView() {     ((ViewGroup)itemView).addView(extraTextView, layoutParams);     viewAdded = true; }  public void removeExtraTextView() {     ((ViewGroup)itemView).removeView(extraTextView);     viewAdded = false; }  public boolean displaysExtraTextView() {     return viewAdded; } 

This is really ugly, because to add view to itemView you need to cast it to ViewGroup (which it doesn't have to be), so ensure that it always will be a ViewGroup or its subclass. Also, you need to provide proper layoutParams to add the extraTextView to itemView.

like image 66
maciekjanusz Avatar answered Oct 14 '22 20:10

maciekjanusz