Search code examples
javaandroidandroid-recyclerviewandroid-cardviewcardview

Expandable CardView using RecyclerView


I am trying to make expandable CardView using Recyclerview. I am able to see the list but when I click on some cardview and scroll then some other view is also expanded. Like when I click on position'0' and scrolls then position '17' also gets expanded..

Here is my code:

My chapter_cardview.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


    <android.support.v7.widget.CardView
        android:id="@+id/cv"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="4dp"
        android:layout_marginEnd="4dp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1.0">

        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/chapter_detail"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginEnd="8dp"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:layout_marginStart="8dp"
                android:text="TextView"
                android:visibility="gone"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/chapter_title" />

            <TextView
                android:id="@+id/chapter_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginBottom="4dp"
                android:layout_marginEnd="8dp"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:layout_marginStart="8dp"
                android:layout_marginTop="4dp"
                android:text="TextView"
                app:layout_constraintBottom_toTopOf="@+id/chapter_detail"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
        </android.support.constraint.ConstraintLayout>
    </android.support.v7.widget.CardView>


</android.support.constraint.ConstraintLayout>

My MyAdapter.java

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    static private List<chapter_title>mDataset;

    // 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 CardView mCardView;
        private TextView mchapter_tile;
        private TextView mchapter_detail;
        public ViewHolder(View itemview) {
            super(itemview);

            mCardView = itemView.findViewById(R.id.cv);
            mchapter_tile = itemview.findViewById(R.id.chapter_title);
            mchapter_detail = itemview.findViewById(R.id.chapter_detail);
        }
    }

    // Provide a suitable constructor (depends on the kind of dataset)
    public MyAdapter(List<chapter_title> myDataset) {
        mDataset = myDataset;
    }

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

        Log.e("viewType: ", ""+viewType);
        if (viewType == 1)
            vh.mchapter_detail.setVisibility(View.VISIBLE);
        else
            vh.mchapter_detail.setVisibility(View.GONE);

        return vh;
    }


    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        holder.mchapter_tile.setText(mDataset.get(position).title);
        holder.mCardView.setTag(position);

        holder.mCardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = (Integer)v.getTag();
                boolean isShown = MyAdapter.mDataset.get(position).isExpanded;
                Log.e("Clicked on:", ""+ position);

                if(isShown)
                {
                    MyAdapter.mDataset.get(position).isExpanded = false;
                    ((CardView)v).findViewById(R.id.chapter_detail).setVisibility(View.GONE);
                }
                else
                {
                    ((CardView)v).findViewById(R.id.chapter_detail).setVisibility(View.VISIBLE);
                    MyAdapter.mDataset.get(position).isExpanded = true;
                }



            }
        });


    }

    @Override
    public int getItemViewType(int position)
    {

      //  Log.e("getItemType, position", position+"");
        if(mDataset.get(position).isExpanded==true)
            return 1;
        else
            return 0;
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
  //      Log.e("list size", mDataset.size()+"");
        return mDataset.size()-50;

    }
}



`

Solution

  • There are a few changes in the adapter file. While binding the view we first check for isExpanded according to the result we setVisibility of the view. Below is the code for Adapter.

    public class MyAdapter extends RecyclerView.Adapter { private List mDataset;

        // 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 CardView mCardView;
            private TextView mchapter_tile;
            private TextView mchapter_detail;
            public ViewHolder(View itemview) {
                super(itemview);
    
                mCardView = itemView.findViewById(R.id.cv);
                mchapter_tile = itemview.findViewById(R.id.chapter_title);
                mchapter_detail = itemview.findViewById(R.id.chapter_detail);
            }
        }
    
        // Provide a suitable constructor (depends on the kind of dataset)
        public MyAdapter(List<chapter_title> myDataset) {
            mDataset = myDataset;
        }
    
        // Create new views (invoked by the layout manager)
        @Override
        public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                       int viewType) {
            // create a new view
            ViewHolder vh = null;
            View view = (View) LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.stack_question_2, parent, false);
            vh = new ViewHolder(view);
            return vh;
        }
    
    
        // Replace the contents of a view (invoked by the layout manager)
        @Override
        public void onBindViewHolder(final ViewHolder holder, final int position) {
            // - get element from your dataset at this position
            // - replace the contents of the view with that element
            final chapter_title chapter_title = mDataset.get(position);
            holder.mchapter_tile.setText(chapter_title.title);
            holder.mCardView.setTag(position);
    
            if (chapter_title.isExpanded)
                holder.mchapter_detail.setVisibility(View.VISIBLE);
            else
                holder.mchapter_detail.setVisibility(View.GONE);
    
            holder.mCardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
    
                    if(mDataset.get(position).isExpanded)
                    {
                        mDataset.get(position).isExpanded = false;
                        ((CardView)v).findViewById(R.id.chapter_detail).setVisibility(View.GONE);
                    }
                    else
                    {
                        ((CardView)v).findViewById(R.id.chapter_detail).setVisibility(View.VISIBLE);
                        mDataset.get(position).isExpanded = true;
                    }
                    //notifyDataSetChanged();
                    notifyItemChanged(position);
                }
            });
    
    
        }
    
        @Override
        public int getItemViewType(int position)
        {
            //  Log.e("getItemType, position", position+"");
            if(mDataset.get(position).isExpanded==true)
                return 1;
            else
                return 0;
        }
    
        // Return the size of your dataset (invoked by the layout manager)
        @Override
        public int getItemCount() {
            //      Log.e("list size", mDataset.size()+"");
            return mDataset.size();
        }
    }
    

    Hope that helps.