Lately I'm experiencing a very strange behavior with CardViews. The scenario is as follows: I have a RecyclerView which uses CardViews as items. The data is dynamic and fetched from the internet, right before the RecyclerView is filled. Every CardView is assigned to an instance of Job.java. The Job has an isPending()-boolean, which returns either true or false (wonder). The background color (and the text) of the card is determined by the isPending()-boolean which is done like this
holder.cv.setCardBackgroundColor(jobs.get(position).isPending()?Color.parseColor("#FFDF72"):holder.cv.getCardBackgroundColor().getDefaultColor());
Until this point it works like a charm.
I then wanted to add an onClickListener which expands the clicked card and then calls notifyItemChanged(position);
Which also works fine. Let's come to the strange behavior.
When I expand a white card (not pending) and close it, everything works as it should. When I do the same with a yellow card (pending) also everything is fine. BUT after selecting a yellow card, whenever I open a white card it turns yellow, when expanded and goes back to white when its reduced again.
I have literally no clue what it can be, because I tried to debugg and at the time the cards sets its color, the boolean "isPending()" is always correct.
The CardView's xml-code:
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:foreground="?android:attr/selectableItemBackground"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="vertical"
app:cardCornerRadius="2dp"
app:cardElevation="6dp"
android:clickable="true"
android:focusable="true">
The RVAdapter's onBindViewHolder-method:
if(jobs.get(position).isPending()) { //the mentioned method expanded due to debug reasons
System.out.println("hsdajdshakl");
holder.cv.setCardBackgroundColor(Color.parseColor("#FFDF72"));
} else holder.cv.setCardBackgroundColor(holder.cv.getCardBackgroundColor().getDefaultColor());
// ... irrelevant code
holder.cv.findViewById(R.id.job_add).setBackgroundColor(holder.cv.getCardBackgroundColor().getDefaultColor());
holder.cv.findViewById(R.id.job_decline).setBackgroundColor(jobs.get(position).isPending()?Color.parseColor("#FFDF72"):holder.cv.getCardBackgroundColor().getDefaultColor());
holder.cv.findViewById(R.id.job_personen).setBackgroundColor(jobs.get(position).isPending()?Color.parseColor("#FFDF72"):holder.cv.getCardBackgroundColor().getDefaultColor());
holder.itemView.setActivated(isExpanded);
holder.itemView.setOnClickListener(v -> {
mExpandedPosition = isExpanded?-1:position;
//notifyItemChanged(previousExpandedPosition);
//jobs.get(position).setPending(jobs.get(position).isPending()); for testing
notifyItemChanged(position);
});
holder.cv.findViewById(R.id.job_decline).setBackgroundColor(jobs.get(position).isPending()?Color.parseColor("#FFDF72"):holder.cv.getCardBackgroundColor().getDefaultColor());
holder.cv.findViewById(R.id.job_personen).setBackgroundColor(jobs.get(position).isPending()?Color.parseColor("#FFDF72"):holder.cv.getCardBackgroundColor().getDefaultColor());
The cv.getCardBackgroundColor()
will return one ColorStateList
, Since you are not using statelist and have not specified any statelist in the XML or in the code, the getDefaultColor()
color will return the same color as the cardBackgroundColor
.
The trick of recyclerview is that it may or may not use the same view for a particular position, lets say there are 10 items, so for the 6th item, it may use the copy of view that was used for the 3rd item, and let's say you 3rd item was of yellow color then for the 6th it will get cv.getCardBackgroundColor()
upon which calling getDefaultColor()
will return yellow color and the reason is explained above.
Solutions are, either you specify ColorStateList
and set a color for different states or you can set color directly by parsing color resource,