-1

This's my code in onCreateViewHolder

@Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

  ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(R.layout.widget_holder, parent, false);
    if (CAT_IMAGE_IDS.get(i).getButton()) {
      LinearLayout ln = new LinearLayout(parent.getContext());
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(230, 250, Gravity.CENTER);
      ln.setLayoutParams(params);
      viewGroup.addView(ln);
      i++;
      return new ItemViewHolder(viewGroup);

    } else if (CAT_IMAGE_IDS.get(i).getDummy()) {

      LinearLayout ln = new LinearLayout(parent.getContext());
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(230, 250, Gravity.CENTER);
      ln.setLayoutParams(params);
      viewGroup.setVisibility(View.INVISIBLE);
      viewGroup.addView(ln);
      i++;
      return new ItemViewHolder(viewGroup);
}

I've been told it's not a good practice to write it there, and it should be inside onBindViewHolder.

I can't seem to figure out how to do it properly even though I took a look at some examples online.

So how should I go about this?

T0uchM3
  • 9
  • 1
  • 5

2 Answers2

0

The onCreateViewHolder() should contain the code which creates the ViewHolder and onBindViewHolder() should populate it with data. Any other approach will cause problems when your collection will contain many elements and will be scrolled by the user.

As far as I see, in your case, the created layout doesn't differ regardless of the CAT_IMAGE_IDS.get(i).getButton() and CAT_IMAGE_IDS.get(i).getDummy() values. It means that the body of onBindViewHolder() should look like this:

ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(R.layout.widget_holder, parent, false);
LinearLayout ln = new LinearLayout(parent.getContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(230, 250, Gravity.CENTER);
ln.setLayoutParams(params);
viewGroup.addView(ln);
return new ItemViewHolder(viewGroup);

Note that I left only the code which actually creates the layout, not the part which sets the visibility - it should be done inside the onBindViewHolder()

public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    if (CAT_IMAGE_IDS.get(position).getButton()){
        holder.itemView.setVisibility(View.VISIBLE);
    } else if (CAT_IMAGE_IDS.get(position).getDummy()){
        holder.itemView.setVisibility(View.INVISIBLE);
    }
}

Typically, the onBindViewHolder() is used to do some more things than just changing the elements' visibility, for example, populate the Views with texts and pictures.

You can check the official guide for some more info.

  • What if I want to add this line `ln.addView(LayoutInflater.from(parent.getContext()).inflate(R.layout.add_button, parent, false));` when .getButton() is true, should i put that in _onBindViewHolder_ after _setVisibility_? – T0uchM3 Apr 11 '19 at 15:28
  • @T0uchM3 If the layout structure of your RecyclerView items differ when a condition is met, you should use the `viewType`. There's a nice response explaining the process [here](https://stackoverflow.com/questions/26245139/how-to-create-recyclerview-with-multiple-view-type). You'll have to implement an additional method - `getItemViewType(int position)` in which you should check if `getButton()` is `true`. Return 0 when true, 1 otherwise. Then, in `onCreateViewHolder()` check if `viewType` is `0`, if yes add the line you want to add. – Wojciech Januszek Apr 12 '19 at 09:12
0

The logic being missed here is simply to utilize the View Holder approach and recycle your views accordingly. Take a look at this sample code:

package yourpackage.goeshere;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import yourpackage.goeshere.R;

public class SampleRecyclerViewAdapter2  extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    //region Vars
    private List<Object> mListObjects;
    private LayoutInflater mInflater;
    private Context context;
    //endregion 

    //region Constructor
    public SampleRecyclerViewAdapter2(@NonNull Context context){
        this.context = context;
        this.mInflater = LayoutInflater.from(this.context);
    }

    //endregion

    //region Initialization
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.your_layout_file_here, parent, false);
        SampleRecyclerViewAdapter2.AdapterHolderType viewHolder2 = new SampleRecyclerViewAdapter2.AdapterHolderType(view);
        return viewHolder2;
    }
    //endregion

    //region Override Methods
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder0, final int position) {

        final Object nonCastObject = mListObjects.get(position);
        if(nonCastObject == null){
            //Decide what to do here
            return;
        }

        //Cast the Holder Here
        SampleRecyclerViewAdapter2.AdapterHolderType holder = (SampleRecyclerViewAdapter2.AdapterHolderType) holder0;

        //Cast the Object Here to your pojo
//      MyCustomObject obj = (MyCustomObject) nonCastObject;

        //Set Fields here; adjust dynamically from cast object
        holder.adapter_sample_recyclerview_iv.setImageResource(R.mipmap.ic_launcher);
        holder.adapter_sample_recyclerview_tv.setText("Some text");

        //Set listeners here
        holder.rootview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Can set a click listener here if need be
            }
        });

        //Handle animations here if you want them
    }

    @Override
    public int getItemCount() {
        return ((this.mListObjects == null) ? 0 : this.mListObjects.size());
    }

    //endregion

    //region Class Methods

    /**
     * Add one object to the list
     * @param position Position to add into
     * @param mObject Single object to update. If null, will be ignored (Call remove instead).
     *                {@link Object}
     */
    public void addOneObject(int position, Object mObject){
        if(mObject == null){
            return;
        }
        if(position < 0 || position > getItemCount()){
            //Out of bounds
            return;
        }
        if(this.mListObjects == null){
            this.mListObjects = new ArrayList<>();
        }
        this.mListObjects.add(position, mObject);
        this.notifyItemChanged(position);
    }

    /**
     * Update one object in the list
     * @param position Position to update
     * @param mObject Single object to update. If null, will be ignored (Call remove instead).
     *                {@link Object}
     */
    public void updateOneObject(int position, Object mObject){
        if(mObject == null){
            return;
        }
        if(position < 0 || position >= getItemCount()){
            //Out of bounds
            return;
        }
        this.mListObjects.set(position, mObject);
        this.notifyItemChanged(position);
    }

    /**
     * Remove a single object from the list
     * @param position Position to remove
     */
    public void removeOneObject(int position){
        if(this.mListObjects != null){
            if(position < 0 || position >= getItemCount()){
                this.mListObjects.remove(position);
                this.notifyItemChanged(position);
            }
        }
    }

    /**
     * Set data list
     * @param mListObjects {@link Object}
     */
    public void setListObjects(List<Object> mListObjects){
        this.mListObjects = mListObjects;
        this.notifyDataSetChanged();
    }
    //endregion

    //region Class Holders

    class AdapterHolderType extends RecyclerView.ViewHolder {

        ImageView adapter_sample_recyclerview_iv;
        RelativeLayout rootview;
        TextView adapter_sample_recyclerview_tv;

        public AdapterHolderType(View itemView) {
            super(itemView);
            this.adapter_sample_recyclerview_tv = itemView.findViewById(R.id.adapter_sample_recyclerview_tv);
            this.rootview = itemView.findViewById(R.id.rootview);
            this.adapter_sample_recyclerview_iv = itemView.findViewById(R.id.adapter_sample_recyclerview_iv);
        }
    }

    //endregion
}

In it, the holder class serves as the direct link to the UI and can be called upon by casting the holder to the type you specified.

Once casted, you can take actions you need by using your object to set values.

In this sample code, I used a generic Object, but you should use whichever object you are using in your class

PGMacDesign
  • 6,092
  • 8
  • 41
  • 78