Search code examples
androidandroid-recyclerviewandroid-cardview

Can't set RecyclerView inside CardView?


enter image description here

I'm trying to put a RecyclerView inside a CardView and create items dynamically.

Obviously, in XML, RecyclerView is set inside CardView tag, but as you can see picture, RecyclerView item is created outside CardView.

(RecyclerView's items are the parts expressed as kg and set in the photo. And CardView is also an item of another RecyclerView.)

What's the problem?

XML

<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginTop="12dp"
    android:layout_marginLeft="12dp"
    android:layout_marginRight="12dp"
    app:cardElevation="10dp">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:id="@+id/ll1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintTop_toTopOf="parent">
            <TextView
                android:id="@+id/workout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="8dp"
                android:text="TEST"/>
            <View
                android:layout_width="match_parent"
                android:layout_height="2dp"
                android:background="@color/light_blue_400"/>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/ll2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintTop_toBottomOf="@+id/ll1">

            <com.google.android.material.button.MaterialButton
                android:id="@+id/delete"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_marginStart="8dp"
                android:layout_marginEnd="4dp"
                style="@style/RoutineButtonStyle"
                android:text="DELETE"
                app:icon="@drawable/ic_delete"/>

            <com.google.android.material.button.MaterialButton
                android:id="@+id/add"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_marginStart="4dp"
                android:layout_marginEnd="8dp"
                style="@style/RoutineButtonStyle"
                android:text="ADD"
                app:icon="@drawable/ic_add"/>
        </LinearLayout>
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/ll2"
            android:orientation="vertical"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

Let me know if you need any other code.


Solution

  • Here is the Activity of your add/delete CardView:

          //Item List if you want to add one or more Items
            private List<MyItem> myItems = new ArrayList<>();
    
    
            private Adapter smallCardAdapter;
    
    
            private int size;
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
    
                RecyclerView recyclerView = findViewById(R.id.rv);
    
                //Creates a new Object in the Adapter.class
                smallCardAdapter = new Adapter();
                recyclerView.setAdapter(smallCardAdapter);
                CardView cardView = findViewById(R.id.cardView);
                MaterialButton delete = findViewById(R.id.delete);
                MaterialButton add = findViewById(R.id.add);
    
    
                //Add onClickListener
                add.setOnClickListener(v -> {
                    try {
                    size = myItems.size();
    
                    //if the value is 0, a new item is created
                    //if you want to delete the card after 0 than you have to change the value to 0
                    if(size == 0){
                        //Creates a new Object in the MyItem.class
                        myItems.add(new MyItem("Set","1kg"));
                    }else{
                        MyItem myItem = myItems.get(0);
    
    
                        //Replace kg with "" to make a Integer
                        String secondString = myItem.getSecondString().replace("kg","");
                        Integer value = Integer.valueOf(secondString);
                        value++;
                        myItem.setSecondString(value+"kg");
                        myItems.set(0,myItem);
    
                    }
    
                    updateAdapter();
                }catch (Exception e){
                    Log.w("MainActivity","Add Button OnClickListener");
                    e.printStackTrace();
                }
                });
    
    
                //Delete onClickListener
                delete.setOnClickListener(v->{
    
                    try {
                        size = myItems.size();
                        //If the value is 0 then canceled to avoid errors
                        if(size == 0){
                            return;
                        }
    
                        MyItem myItem = myItems.get(0);
    
                        //Replace kg with "" to make a Integer
                        String secondString = myItem.getSecondString().replace("kg","");
                        Integer value = Integer.valueOf(secondString);
    
                        //if the value is one or lower
                        if(value <= 1){
                            //The card will deleted after updateAdapter();
                            myItems.clear();
                        }else{
                            value--;
                            myItem.setSecondString(value+"kg");
                            myItems.set(0,myItem);
                        }
                        updateAdapter();
                    }catch (Exception e){
                        Log.w("MainActivity","Delete Button OnClickListener");
                        e.printStackTrace();
                    }
    
                });
    
    
            }
            private void updateAdapter(){
                try {
                    smallCardAdapter.setItems(myItems);
            }catch (Exception e){
                    Log.w("MainActivity","updateAdapter");
                    e.printStackTrace();
                }
    
            }
    

    The custom Item called MyItem:

    public class MyItem {
    
        String firstString;
        String secondString;
    
        public MyItem(String firstString,String secondString){
            this.firstString = firstString;
            this.secondString = secondString;
        }
        public String getFirstString() {
            return firstString;
        }
    
        public void setFirstString(String firstString) {
            this.firstString = firstString;
        }
    
        public String getSecondString() {
            return secondString;
        }
    
    
    
           public void setSecondString(String secondString) {
                this.secondString = secondString;
            }
        }
    

    The Adapter.java creates a smallCard:

    public class Adapter extends RecyclerView.Adapter<Adapter.SmallCardHolder> {
    
    
    
        private List<MyItem> items = new ArrayList<>();
    
        @NonNull
        @Override
        public SmallCardHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            //                                     I created a new smallcard for the CardView
            View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.smallcard, parent, false);
            SmallCardHolder smallCardHolder = new SmallCardHolder(itemView);
            return smallCardHolder;
        }
    
        @Override
        public void onBindViewHolder(@NonNull final SmallCardHolder holder, int position) {
    
            //get the current item of the position
            MyItem myItem = items.get(position);
    
            String firstString = myItem.getFirstString();
            String secondString = myItem.getSecondString();
    
            holder.textViewSet.setText(firstString);
            holder.textViewkg.setText(secondString);
        }
    
    
        @Override
        public int getItemCount () {
            return items.size();
        }
    
        public void setItems(List <MyItem> items) {
            this.items = items;
            notifyDataSetChanged();
        }
    
    
        class SmallCardHolder extends RecyclerView.ViewHolder {
    
    
            //Here are the TextView's of the smallcard (smallcard.xml)
            private TextView textViewSet;
            private TextView textViewkg;
    
            public SmallCardHolder(@NonNull View itemView) {
                super(itemView);
                textViewSet = itemView.findViewById(R.id.set);
                textViewkg = itemView.findViewById(R.id.kg);
    
            }
        }
    }
    

    Create a new layout with name called smallcard.xml for the Adapter.java:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
        <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
            <TextView
                    android:id="@+id/set"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Set"
                    android:layout_centerVertical="true"
                    android:textSize="18sp"
                    android:layout_marginStart="5dp"
                    android:textColor="?attr/colorPrimary"
                    android:textStyle="bold"/>
    
            <TextView
                    android:id="@+id/kg"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="kg"
                    android:layout_toRightOf="@id/set"
                    android:layout_marginLeft="55dp"
                    android:layout_centerVertical="true"
                    android:textColor="?attr/colorPrimary"
                    android:textSize="16sp"
                    android:layout_marginRight="10dp"
                    android:maxLines="1"/>
        </RelativeLayout>
    </RelativeLayout>
    

    In your XML you have to give the CardView a name. I called it cardView. Here is the code android:id="@+id/cardView"

    Result:

    Result

    You will find more information as comments in the code.