5
votes

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 :(

1
How do you define your favResultsLayout? - Médéric
obviously you have to store expanded items(set of expanded item's positions should be ok) in Adapter or in item itself(not posible now with String you have to use custom class like Item { public String String1; public boolean Expanded } ) and use this information to setup view holder in onBindViewHolder .... view holders count used by adapter != items count of underlaying data ... remeber about this - Selvin
Thanks for the reply! Below are the codes for favResultsLayout favResultsLayout = (RelativeLayout) itemView.findViewById(R.id.fav_results_layout); The xml: <RelativeLayout android:id="@+id/fav_results_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone"> <!--GridView here--> </RelativeLayout> - SpencerRoi
@SpencerRoi it doesn't matter ... try to implement my comment - Selvin
Hi, I did something similar, where I stored the position of the views that were expanded in an arraylist and in onBindViewHolder i set the expanded layout to GONE by default and only set the visibility to VISIBLE only for views that are in the arraylist. It didn't work though.. I also tried adding the views into an ArrayList and comparing it.. No luck too. Was that a right approach? - SpencerRoi

1 Answers

2
votes

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
}