javaandroidandroid-recyclerviewcardview

RecyclerView cardview Onclick duplicate effects when scrolling


I'm making my first app (calendar), clicking the cardview item applies the same effect (changing Textview text color and Imageview background) to other items when scrolling the RecyclerView

in the main activity

    RecyclerView daysRecyclerView;
    DaysAdapter daysAdapter;
    private RecyclerView.LayoutManager horizontalLayout;

    ArrayList<DaysModel> daysModels;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_calendar);

       

        daysModels = getDaysList();
        initDaysRecycleview();

    }

    private void initDaysRecycleview(){
        daysRecyclerView = findViewById(R.id.daysRecyclerView);
        daysRecyclerView.setHasFixedSize(true);

        horizontalLayout = new LinearLayoutManager(this,RecyclerView.HORIZONTAL,false);
        daysAdapter = new DaysAdapter(daysModels);


        daysRecyclerView.setLayoutManager(horizontalLayout);
        daysRecyclerView.setAdapter(daysAdapter);

        daysAdapter.setOnItemClickListener(new DaysAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int position) {
                dayClickHandler(position, 1);
            }
        });

    }
    public void dayClickHandler(int position, int change){
        daysModels.get(position).changeDayHighlight(change);
        daysAdapter.notifyItemChanged(position);
    }

    private ArrayList<DaysModel> getDaysList(){
        //Not accurate used for testing
        ArrayList<DaysModel> models = new ArrayList<DaysModel>();
        String[] dayName ={"SAT","SUN","MON","TUE","WED","THU","FRI","SAT","SUN","MON","TUE","WED","THU","FRI","SAT","SUN","MON","TUE","WED","THU","FRI","SAT","SUN","MON","TUE","WED","THU","FRI","SAT","SUN","MON"};

        int i,j;
        for (i = 0;i <dayName.length;i++){
            j =i+1;
            models.add(new DaysModel(dayName[i], j, 0, false));
        }
        return models;
    }

I'm using an interface for the onClickListener.

ViewHolder

public class DaysViewHolder extends RecyclerView.ViewHolder {
    TextView hDayName,hDayNumber;
    ImageView currentDayHighlight;
    CardView dayCard;

    public DaysViewHolder(View itemView, DaysAdapter.OnItemClickListener listener) {
        super(itemView);
        this.hDayName = itemView.findViewById(R.id.dayName);
        this.hDayNumber = itemView.findViewById(R.id.dayNumber);
        this.currentDayHighlight = itemView.findViewById(R.id.dayHihlight);
        this.dayCard = itemView.findViewById(R.id.dayCard);

        dayCard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null) {
                    int position = getAdapterPosition();
                    if(position != RecyclerView.NO_POSITION){
                        listener.onItemClick(position);
                    }
                }
            }
        });

    }

}

Adapter

    public class DaysAdapter extends RecyclerView.Adapter<DaysViewHolder> {
    Context context;
    ArrayList<DaysModel> daysModels;

    OnItemClickListener mListener;

    public interface OnItemClickListener{
        void onItemClick(int position);
    }
    public void setOnItemClickListener(OnItemClickListener listener){
        mListener = listener;
    }

    public DaysAdapter(ArrayList<DaysModel> daysModels) {
        this.daysModels = daysModels;
    }

    @NonNull
    @Override
    public DaysViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.day_card,parent,false);
        DaysViewHolder daysViewHolder = new DaysViewHolder(view, mListener);
        return daysViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull DaysViewHolder holder, int position) {
        DaysModel currentItem = daysModels.get(position);
        holder.hDayName.setText(currentItem.getDayName());
        holder.hDayNumber.setText(String.valueOf(currentItem.getDayNumber()));
        
        if(currentItem.isDayHighlighted() == 1){
            holder.currentDayHighlight.setBackgroundResource(R.drawable.tiny_background);
            holder.hDayNumber.setTextColor(Color.BLACK);
        }


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

Solution

  • All you need is to set else part for you if condition in bind method of Adapter class. So change your bind method to something like this:

    @Override
    public void onBindViewHolder(@NonNull DaysViewHolder holder, int position) {
        DaysModel currentItem = daysModels.get(position);
        holder.hDayName.setText(currentItem.getDayName());
        holder.hDayNumber.setText(String.valueOf(currentItem.getDayNumber()));
        
        if(currentItem.isDayHighlighted() == 1){
            holder.currentDayHighlight.setBackgroundResource(R.drawable.tiny_background);
            holder.hDayNumber.setTextColor(Color.BLACK);
        }else{
    
            holder.currentDayHighlight.setBackgroundResource(/*what ever you want for default situation*/);
            holder.hDayNumber.setTextColor(/* for example Color.White*/);
         }
    
    }