Search code examples
androidandroid-recyclerviewratingbar

How to make a RecyclerView with a ratngBar inside it so the the user can rate the RecylerView items


How to handle user feedback via ratingbars embedded in RecyclerView?

activity_main.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="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        android:padding="4dp"
        android:background="@android:color/darker_gray"/>

</android.support.constraint.ConstraintLayout>

food_list.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:cardCornerRadius="4dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="4dp">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="80dp"
            android:layout_height="80dp"
            app:srcCompat="@mipmap/ic_launcher" />

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="18dp"
            android:layout_marginStart="48dp"
            android:text="Food Name"
            app:layout_constraintStart_toEndOf="@+id/imageView"
            app:layout_constraintTop_toTopOf="parent" />

        <RatingBar
            android:id="@+id/ratingBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="16dp"
            android:layout_marginTop="5dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView" />

    </RelativeLayout>
</android.support.v7.widget.CardView>

FoodItem.java

package com.example.recyclerviewproject2;

public class FoodItem {
    private int foodImage;
    private String foodName;
    private int foodRating;

    public FoodItem(int foodImage, String foodName, int foodRating) {
        this.foodImage = foodImage;
        this.foodName = foodName;
        this.foodRating = foodRating;
    }

    public int getFoodImage() {
        return foodImage;
    }

    public void setFoodImage(int foodImage) {
        this.foodImage = foodImage;
    }

    public String getFoodName() {
        return foodName;
    }

    public void setFoodName(String foodName) {
        this.foodName = foodName;
    }

    public int getFoodRating() {
        return foodRating;
    }

    public void setFoodRating(int foodRating) {
        this.foodRating = foodRating;
    }
}

This is

FoodAdapter.java

package com.example.recyclerviewproject2;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;

import java.util.ArrayList;

public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {

    private ArrayList<FoodItem> arrayList;

    public static class FoodViewHolder extends RecyclerView.ViewHolder {

        private ImageView viewHolderImageView;
        private TextView  viewHolderTextView;
        private RatingBar viewHolderRatigBar;

        public FoodViewHolder(@NonNull View itemView) {
            super(itemView);

            viewHolderImageView = itemView.findViewById(R.id.imageView);
            viewHolderTextView = itemView.findViewById(R.id.textView);
            viewHolderRatigBar = itemView.findViewById(R.id.ratingBar);
        }
    }

    public FoodAdapter(ArrayList<FoodItem> foodList) {
        arrayList = foodList;
    }

    @NonNull
    @Override
    public FoodViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.food_item, viewGroup, false);
        FoodViewHolder foodViewHolder = new FoodViewHolder(view);
        return foodViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull FoodViewHolder foodViewHolder, int i) {
        FoodItem currentItem = arrayList.get(i);
        foodViewHolder.viewHolderImageView.setImageResource(currentItem.getFoodImage());
        foodViewHolder.viewHolderTextView.setText(currentItem.getFoodName());
        foodViewHolder.viewHolderRatigBar.setRating(currentItem.getFoodRating());
    }

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

And this is

ActivityMain.java

package com.example.recyclerviewproject2;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;

import java.util.ArrayList;

import static android.support.v7.widget.RecyclerView.*;

public class MainActivity extends AppCompatActivity {

    private ArrayList<FoodItem> foodList;
    private RecyclerView recyclerView;
    private Adapter adapter;
    private LayoutManager layoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        createFoodList();
        buildRecyclerView();
    }

    private void createFoodList() {
        foodList = new ArrayList<>();
        foodList.add(new FoodItem(R.drawable.a, "a", 0));
        foodList.add(new FoodItem(R.drawable.b, "b", 0));
        foodList.add(new FoodItem(R.drawable.c, "c", 0));
        foodList.add(new FoodItem(R.drawable.d, "d", 0));
        foodList.add(new FoodItem(R.drawable.e, "e", 0));
        foodList.add(new FoodItem(R.drawable.f, "f", 0));
        foodList.add(new FoodItem(R.drawable.g, "g", 0));
        foodList.add(new FoodItem(R.drawable.h, "h", 0));
        foodList.add(new FoodItem(R.drawable.i, "i", 0));
        foodList.add(new FoodItem(R.drawable.j, "j", 0));
        foodList.add(new FoodItem(R.drawable.k, "k", 0));
        foodList.add(new FoodItem(R.drawable.l, "n", 0));
        foodList.add(new FoodItem(R.drawable.m, "m", 0));
    }

    private void buildRecyclerView() {
        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(this);
        adapter = new FoodAdapter(foodList);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);
    }
}

Solution

  • You need to use add the OnRatingBarChangeListener to handle the OnRatingBarChanged event.

    Add the necesary code to the onBindViewHolder method:

    @Override
    public void onBindViewHolder(@NonNull FoodViewHolder foodViewHolder, int i) {
        FoodItem currentItem = arrayList.get(i);
        foodViewHolder.viewHolderImageView.setImageResource(currentItem.getFoodImage());
        foodViewHolder.viewHolderTextView.setText(currentItem.getFoodName());
    
        foodViewHolder.viewHolderRatigBar.setRating(currentItem.getFoodRating());       
        foodViewHolder.viewHolderRatigBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener(){
            @Override
            public void onRatingBarChanged(RatingBar ratingBar, float rating, boolean fromUser){
                currentItem.setFoodRating(rating);
            }
        }
    }
    

    NOTE: The value "rating" passed to the onRatingBarChanged() method is of type float so you will need to change your FoodItem class to accommodate this type.

    If you wish to persist this value you will need to include some mechanism to save the new rating value--perhaps in a database.