T1M T1M - 2 months ago 15
Java Question

Recycleview expanding multiple iterms

I have created some code which pulls data from a database and then populates a cardView. The cardView rows have a hidden (gone) textView which I want to enable when the card is clicked and hence expand the view.
All this seems to be working OK but for some reason it expands not just item 1 but also another item which I obviously don't want and see no reason why it expands.

Here is my Adapter

import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.blackout.kfzquiz.model.Product;

import java.util.ArrayList;
import java.util.List;

/**
* Created by Sundown on 01/10/2016.
*/

public class MyAdapter2 extends RecyclerView.Adapter<MyAdapter2.ViewHolder> {
private String[] kennzeichen_array;
private String[] stadt_array;
private int length;

// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder{
//each data item is just a string in this case
public TextView kennzeichen;
public TextView hiddenTextView;

public ViewHolder(View v){
super(v);
kennzeichen = (TextView) v.findViewById(R.id.tv);
hiddenTextView = (TextView) v.findViewById(R.id.textView8);
}
}

// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter2(List<Product> myItems){
length = myItems.size();

String[] mStrings = new String[myItems.size()];
String[] stadtStrings = new String[myItems.size()];
for(int i=0;i<myItems.size();i++) {
mStrings[i] = myItems.get(i).getkfz();
stadtStrings[i] = myItems.get(i).getStadt();
}
kennzeichen_array = mStrings;
stadt_array = stadtStrings;

}

// Create new views (invoked by the layout manager)
@Override
public MyAdapter2.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
LayoutInflater inflater = LayoutInflater.from(
parent.getContext());
View v =
inflater.inflate(R.layout.my_text_view, parent, false);

// set the view's size, margins, paddings and layout parameters
MyAdapter2.ViewHolder vh = new MyAdapter2.ViewHolder(v);
return vh;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(final MyAdapter2.ViewHolder holder, final int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.kennzeichen.setText(kennzeichen_array[position]);
holder.hiddenTextView.setText(stadt_array[position]);

holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Clicked", String.valueOf(holder.getAdapterPosition()));
if (holder.hiddenTextView.getVisibility() == View.VISIBLE){
holder.hiddenTextView.setVisibility(View.GONE);
}
else{
holder.hiddenTextView.setVisibility(View.VISIBLE);
}
}
});
}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return length;
}
}


And some screenshots

Nothing ExpandedClicked on first itemAnother also expanded??

Thanks in advance

Answer

Recycler view reuse items - it creates fixed amount of them that fit to the screen, and reuse them as you scroll. So, for example, if you have to show 30 items, recyclerView will create only let say 7 items , and reuse them as you scroll. Therfore item 1 will be also item 8, item 15 and so on. When you make your text view visible on particular item, it stay visible when you scroll, because it is the same item.

The solution is to track information about particular TextView visibility at given position, and apply it when you scroll to that position.

So, what you need to do:

Create a boolean array that will hold information about item visibility at given position

private boolean[] shouldBeHidden;

Next, initialize it in constructor:

    length = myItems.size();

    String[] mStrings = new String[myItems.size()];
    String[] stadtStrings = new String[myItems.size()];
    shouldBeHidden = new boolean[length];
    for(int i=0;i<myItems.size();i++) {
        mStrings[i] = myItems.get(i).getkfz();
        stadtStrings[i] = myItems.get(i).getStadt();
        shouldBeHidden[i] = true;
    }

Finaly, set visibility in OnBindViewHolder method:

        holder.kennzeichen.setText(kennzeichen_array[position]);
        holder.hiddenTextView.setText(stadt_array[position]);
        final TextView myHiddenText = holder.hiddenTextView;

        if (shouldBeHidden[position]){
            myHiddenText.setVisibility(View.GONE);
        }
        else{
            myHiddenText.setVisibility(View.VISIBLE);
        }

  holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("Clicked", String.valueOf(holder.getAdapterPosition()));
        if (myHiddenText.getVisibility()==View.VISIBLE){
            myHiddenText.setVisibility(View.GONE);
            shouldBeHidden[position] = true;
        }
        else{
            myHiddenText.setVisibility(View.VISIBLE);
            shouldBeHidden[position] = false;
        }

    }
});