SpencerRoi SpencerRoi - 2 months ago 12
Android Question

RecyclerView Viewholder reusing

I am creating a

RecyclerView
which will expand itself when the user touches it and closes itself when the user touches it again. Below is my code:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecViewHolder> {
ArrayList<String> values;
ArrayList<Integer> expandedPosition;
public static class RecViewHolder extends RecyclerView.ViewHolder {
...
private boolean resultsOpened = false;
...
RelativeLayout favHeaderLayout;
RelativeLayout favResultsLayout;

public RecViewHolder (View itemView) {
super(itemView);
favHeaderLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!resultsOpened) {
expandLayout();
} else {
favResultsLayout.setVisibility(View.GONE);
resultsOpened = false;
}
}
});

}

public void expandLayout() {
favResultsLayout.setVisibility(View.VISIBLE);
resultsOpened = true;
//I populate my expanded layout here
}
}

public RecyclerViewAdapter (Context context, ArrayList<String> values) {
this.context = context;
this.values= values;
}

@Override
public RecViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_file, parent, false);
RecViewHolder recViewHolder= new RecViewHolder(v);
return recViewHolder;
}

@Override
public void onBindViewHolder(RecViewHolder recViewHolder , int position) {
}

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}

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

}


When I touch the first view, it should expand itself. However, when the adapter has more data and I touch the first view, the view expands and another view at the bottom of the
RecyclerView
(e.g. the 8th view) expands too. How do I ensure that only the view that have been touched expand the the other stays close?

EDIT

I've tried storing the expanded Views position in an arraylist and in
onBindViewHolder
, check which views are expanded and expand them only:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecViewHolder> {
ArrayList<String> values;
ArrayList<Integer> expandedPosition;
public static class RecViewHolder extends RecyclerView.ViewHolder {
...
private boolean resultsOpened = false;
...
RelativeLayout favHeaderLayout;
RelativeLayout favResultsLayout;

public RecViewHolder (View itemView) {
super(itemView);


}

}

public RecyclerViewAdapter (Context context, ArrayList<String> values) {
this.context = context;
this.values= values;
}

@Override
public RecViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_file, parent, false);
RecViewHolder recViewHolder= new RecViewHolder(v);
return recViewHolder;
}

@Override
public void onBindViewHolder(RecViewHolder recViewHolder , int position) {
recViewHolder.favResultsLayout.setVisibility(View.GONE);
for(int i= 0; i < expandedPosition.size(); i ++){
recViewHolder.favResultsLayout.setVisibility(View.VISIBLE);
}
recViewHolder.favHeaderLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!expandedPosition.contains(position)) {
expandLayout(recViewHolder);
expandedPosition.add(position);
} else {
recViewHolder.favResultsLayout.setVisibility(View.GONE);
for(int i = 0; i < expandedPosition.size(); i ++){
if (expandedPosition.get(i) == position){
expandedPosition.remove(i);
}
}
}
}
});
}
public void expandLayout() {
favResultsLayout.setVisibility(View.VISIBLE);
//I populate my expanded layout here
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}

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

}


Still no luck :(

Answer

As the class name says it is all about recycling ...

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecViewHolder> {
    ArrayList<String> values;
    SparseBooleanArray expanded = new SparseBooleanArray();
    public static class RecViewHolder extends RecyclerView.ViewHolder {
        //EDIT!!!!!
        public RecViewHolder (View itemView, final RecyclerViewAdapter adapter) {
        //rest of the code ...
        favHeaderLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { 
                final int currentPosition = getAdapterPosition();
                //is a view at current position expanded?
                if(adapter.expanded.get(currentPosition ))
                    //if so it shouldn't be
                    adapter.expanded.delete(getAdapterPosition(currentPosition));
                else
                    //if not, expand
                    adapter.expanded.put(currentPosition, true);
                //wheeee inform the adapter to rebind
                adapter.notifyItemChanged(currentPosition);
                //setupExpanded(expanded.get(currentPosition)); 
            }
        });
        }
        protected void setupExpanded(boolean state) {
        //ONLY hide show layouts based on state
        }
    }
    @Override
    public RecViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_file, parent, false);
        RecViewHolder recViewHolder= new RecViewHolder(v, this);
        return recViewHolder;
    }

    @Override
    public void onBindViewHolder(RecViewHolder recViewHolder , int position)    {
        //this line should be self explanatory
        recViewHolder.setupExpanded(expanded.get(position));
    }

    //rest of the code
}
Comments