BekaKK
BekaKK

Reputation: 2243

How to add custom view inside RecyclerView.Adapter

I have a RecyclerView and successfully adapted some data. I have a problem. In the onBindViewHolder method, I am trying to add a custom view in a linear layout. The custom view is successfully added, but in scroll up or down views are duplicated. I want to add only once with items.

My code:

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

    public ArrayList<Train> trains;
    public Context context;
    private LayoutInflater inflater;
    public OnItemClickListener mOnItemClickListener;

    public void setmOnItemClickListener(OnItemClickListener mOnItemClickListener) {
        this.mOnItemClickListener = mOnItemClickListener;
    }


    public class GenericViewHolder extends RecyclerView.ViewHolder {
        public TextView stationName;
        public LinearLayout vagoncontainer;

        public GenericViewHolder(View view) {
            super(view);
            stationName = (TextView) view.findViewById(R.id.station_item_name);
            vagoncontainer = (LinearLayout) view.findViewById(R.id.vagon_container);


        }
    }

    public TrainsAdapter(Context context, ArrayList<Train> trains) {
        this.context = context;
        this.trains = trains;
        inflater = LayoutInflater.from(context);


    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.trains_adapter_item, parent, false);
        GenericViewHolder holder = new GenericViewHolder(view);
        return holder;


    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        if (holder instanceof GenericViewHolder) {
            GenericViewHolder genericViewHolder = (GenericViewHolder) holder;
            Train train = trains.get(position);
            ArrayList<Vagons> vagons = train.getVagons();
            for (int i = 0; i < vagons.size(); i++) {
                LayoutInflater layoutInflater = LayoutInflater.from(context);
                LinearLayout vagonView = (LinearLayout) layoutInflater.inflate(R.layout.trains_vagon_child, null);
                Button button = (Button) vagonView.findViewById(R.id.button);
                if (vagons.get(i).getEnable().equals("1"))
                    button.setVisibility(View.VISIBLE);
                else
                    button.setVisibility(View.GONE);
                button.setText(vagons.get(i).getName() + " " + vagons.get(i).getAmount());
                genericViewHolder.vagoncontainer.addView(vagonView);
            }


            genericViewHolder.stationName.setText(train.getDeparture());

        }
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getItemCount() {
        return trains.size();
    }

    public Train getItem(int position) {
        return trains.get(position);
    }

    public interface OnItemClickListener {
        void onItemClick(View view, int position);
    }
}

How can I solve my problem?

Upvotes: 3

Views: 4463

Answers (3)

MadScientist
MadScientist

Reputation: 2164

Basically RecyclerView reuses your viewHolder. So as per the RecyclerView doc here You have to reset the views everytime inside the onBindViewHolder() method,

And based on this

but in scroll up or down views are dublicated.I want to add only one time with items

you need to removeAllViews inside your vagonContainer viewgroup

so your bind holder will look like

if (holder instanceof GenericViewHolder) {
        GenericViewHolder genericViewHolder = (GenericViewHolder) holder;
        Train train = trains.get(position);
        ArrayList<Vagons> vagons = train.getVagons();

        // this is very important. removing all view
        genericViewHolder.vagoncontainer.removeAllViews();
......

Similar question here

Upvotes: 0

egoldx
egoldx

Reputation: 1520

This will fix your problem, but it is not effective (it won't be scrolling smoothly for trains with large amount of vagons - inflating Views is expensive), since you will be removing and recreating views in that LinearLayout representing row in ListView. Either reconsider your row layout or create some pseudo recyling in your row view.

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
    if (holder instanceof GenericViewHolder) {
        GenericViewHolder genericViewHolder = (GenericViewHolder) holder;
        genericViewHolder.vagoncontainer.removeAllViews();
        Train train = trains.get(position);
        ArrayList<Vagons> vagons = train.getVagons();
        for (int i = 0; i < vagons.size(); i++) {
            LayoutInflater layoutInflater = LayoutInflater.from(context);
            LinearLayout vagonView = (LinearLayout) layoutInflater.inflate(R.layout.trains_vagon_child, null);
            Button button = (Button) vagonView.findViewById(R.id.button);
            if (vagons.get(i).getEnable().equals("1"))
                button.setVisibility(View.VISIBLE);
            else
                button.setVisibility(View.GONE);
            button.setText(vagons.get(i).getName() + " " + vagons.get(i).getAmount());
            genericViewHolder.vagoncontainer.addView(vagonView);
        }

        genericViewHolder.stationName.setText(train.getDeparture());
    }
}

Upvotes: 1

FarshidABZ
FarshidABZ

Reputation: 4123

You can use core adapter

It's a simple lib to Support Any Type of items in recyclerview with no pain.

Upvotes: 0

Related Questions