Search code examples
javaandroid-studiosharedpreferencesbackground-colorcardview

How can I change Card View background color on click and keep the color change persistent?


When I click on Card, the color changes sometimes and sometimes it doesn't. Many a time it happens that the changed color does not retain. I want to create something like Facebook Notifications page where we come to know about read notifications by the changed color of the card. But there is some problem with my adapter class. Please help me.

I tried saving the color states in shared preferences, but the desired output is not achieved. I think the issue must be with my toggle logic. I don't have any professional experience with Android coding. Please help me. My app is in final stage.

public class PyqAdapter extends RecyclerView.Adapter<PyqAdapter.ViewHolder> {
    private final Context mCtx;
    private final List<PyqModel> pyqModelList;
    private final int defaultBackgroundColor;
    private final int selectedBackgroundColor;
    private final Set<Integer> selectedPositions;

    private static final String PREFS_NAME = "PyqAllItems";
    private static final String SELECTED_ITEMS_KEY = "PyqSelectedItems";

    public PyqAdapter(Context mCtx, List<PyqModel> pyqModelList) {
        if (mCtx == null) {
            throw new IllegalArgumentException("Context cannot be null");
        }
        this.mCtx = mCtx;
        this.pyqModelList = pyqModelList;
        this.selectedPositions = new HashSet<>();

        // Load colors based on the current theme
        Resources res = mCtx.getResources();
        int nightModeFlags = res.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
        if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) {
            defaultBackgroundColor = ContextCompat.getColor(mCtx, R.color.defaultBackgroundDark);
            selectedBackgroundColor = ContextCompat.getColor(mCtx, R.color.selectedBackgroundDark);
        } else {
            defaultBackgroundColor = ContextCompat.getColor(mCtx, R.color.defaultBackgroundLight);
            selectedBackgroundColor = ContextCompat.getColor(mCtx, R.color.selectedBackgroundLight);
        }

        // Load selected states from SharedPreferences
        SharedPreferences prefs = mCtx.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
        Set<String> selectedItems = prefs.getStringSet(SELECTED_ITEMS_KEY, new HashSet<>());
        for (String position : selectedItems) {
            selectedPositions.add(Integer.parseInt(position));
        }

        // Set selection state on models based on loaded positions
        for (int i = 0; i < pyqModelList.size(); i++) {
            PyqModel model = pyqModelList.get(i);
            model.setSelected(selectedPositions.contains(i));
        }
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.pyq_rv_layout, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        final PyqModel temp = pyqModelList.get(position);

        // Set text views
        holder.textView.setText(temp.getPdfName());
        holder.serialNumber.setText(String.valueOf(position + 1));
        holder.pyqTopics.setText(temp.getPyqTopics());

        // Use holder.getAdapterPosition() to get the current position
        int adapterPosition = holder.getAdapterPosition();
        if (adapterPosition == RecyclerView.NO_POSITION) {
            return;
        }

        // Set background color based on selection state
        if (temp.isSelected()) {
            holder.cardView.setCardBackgroundColor(selectedBackgroundColor);
        } else {
            holder.cardView.setCardBackgroundColor(defaultBackgroundColor);
        }

        holder.cardView.setOnClickListener(v -> {
            SharedPreferences prefs = mCtx.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = prefs.edit();
            Set<String> selectedItems = new HashSet<>();
            for (int pos : selectedPositions) {
                selectedItems.add(String.valueOf(pos));
            }
            selectedPositions.add(adapterPosition);
            editor.putStringSet(SELECTED_ITEMS_KEY, selectedItems);
            // Notify adapter to refresh views
            notifyItemChanged(adapterPosition);
            editor.apply();

            // Launch ViewPdf activity
            Intent i = new Intent(holder.cardView.getContext(), ViewPdf.class);
            i.putExtra("pdfName", temp.getPdfName());
            i.putExtra("pdfUrl", temp.getPdfUri());
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            holder.cardView.getContext().startActivity(i);
        });
    }






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

    public static class ViewHolder extends RecyclerView.ViewHolder {
        CardView cardView;
        TextView textView, serialNumber, pyqTopics;

        public ViewHolder(View itemView) {
            super(itemView);
            cardView = itemView.findViewById(R.id.pyqCardView);
            textView = itemView.findViewById(R.id.pyqTitle);
            serialNumber = itemView.findViewById(R.id.serialNumber);
            pyqTopics = itemView.findViewById(R.id.pyqTopics);
        }
    }
}

Solution

  • Add this :

    private List<Integer> highlightedPositions;
    

    instead of this:

    private final Set<Integer> selectedPositions;
    

    in your adapter class.

    Then use these two function to save and then load the positions of the cards selected by the User.

    private void loadHighlightedPositions() {
        SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", MODE_PRIVATE);
        String positionsString = sharedPreferences.getString("highlightedPositions", "");
        if (!positionsString.isEmpty()) {
            String[] positionsArray = positionsString.split(",");
            for (String position : positionsArray) {
                highlightedPositions.add(Integer.parseInt(position));
            }
        }
    }
    
    private void saveHighlightedPositions() {
        SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        StringBuilder positionsString = new StringBuilder();
        for (int position : highlightedPositions) {
            positionsString.append(position).append(",");
        }
        if (positionsString.length() > 0) {
            positionsString.deleteCharAt(positionsString.length() - 1); // Remove the trailing comma
        }
        editor.putString("highlightedPositions", positionsString.toString());
        editor.apply();
    }
    

    Then use this in onBindviewHolder() Method :

    if (highlightedPositions.contains(position)) {
        holder.itemView.setBackgroundColor(selectedBackgroundColor); // Change to your desired color
    } else {
        holder.itemView.setBackgroundColor(defaultBackgroundColor); // Default color
    }
    

    Then use these two Functions in the adapter class to add and remove position based on whether position is already selected or not.

    public void addPosition(int position) {
        if (!highlightedPositions.contains(position)) {
            highlightedPositions.add(position);
            saveHighlightedPositions();
            notifyItemChanged(position);
        }
    }
    
    public void removePosition(int position) {
        if (highlightedPositions.contains(position)) {
            highlightedPositions.remove((Integer) position);
            saveHighlightedPositions();
            notifyItemChanged(position);
        }
    }
    

    Then use this on onClickListener for your card item:

    holder.itemView.setOnClickListener(v -> {
        if (highlightedPositions.contains(position)) {
            highlightedPositions.remove((Integer) position);
        } else {
            highlightedPositions.add(position);
        }
        saveHighlightedPositions();
        notifyItemChanged(position);
    });
    

    P.S You need to make changes in Shared Preferences storage approach. Hope that helps.