Setting CardView elevation programmatically

Vancore picture Vancore · Feb 22, 2017 · Viewed 9.7k times · Source

I do not know if this approach is the best, but I have the following problem:

I want a list item (a CardView) in a RecyclerView to be animated when it's button was clicked, so that this button, some other views inside this item and the background of the CardView changes.

I am catching the animateChange from a custom RecyclerView.ItemAnimator: (until now the animation is just a fade defined in the xml via animateLayoutChanges)

public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder, @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
    Log.d("Animation", "Test");
    final MyAdapter.MyViewHolder viewHolder = (MyAdapter.MyViewHolder) newHolder;

    viewHolder.mButtons.setVisibility(View.GONE);
    viewHolder.mHints.setVisibility(View.GONE);
    viewHolder.mImageView.setVisibility(View.GONE);

    ViewGroup.LayoutParams layoutParams = viewHolder.containerCardView.getLayoutParams();
    layoutParams.height = 192;
    viewHolder.containerCardView.setLayoutParams(layoutParams);
    viewHolder.containerCardView.setBackgroundResource(R.drawable.some_background);
    viewHolder.containerCardView.setElevation(20f);

    return true;
}

As you can see, I am setting the background manually in the animateChange. Everything works fine (or lets say at least as expected) except for the elevation of the CardView. I tried to set the elevation by hand, but there is no elevation shown.

EDIT______

My CardView has an ImageView and a button inside it. When pressing the button, the button itself and the picture should fade out and there shall be a red line on the right side of the cardView. I tried to achieve that by setting the background (with setBackgroundResource) to this:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
           android:shape="rectangle">
        <gradient
            android:angle="180"
            android:centerColor="@android:color/transparent"
            android:centerX="0.1"
            android:startColor="@android:color/holo_red_dark"/>
        <corners
            android:bottomLeftRadius="2dip"
            android:bottomRightRadius="2dip"
            android:topLeftRadius="2dip"
            android:topRightRadius="2dip"/>
    </shape>
</item>

<item android:right="4dp">
    <shape android:shape="rectangle">
        <solid android:color="@android:color/white" />
    </shape>
</item>
</layer-list>

Which is just an xml drawable with a red line on the right. Do you have any suggestions for another way to approach my goal?

Answer

Massimo picture Massimo · Feb 22, 2017

You should call setCardElevation rather than setElevation. The second one modifies the property elevation, which all View subclasses have since Lollipop (API level 21).

And DON'T USE setBackgroundResource: the card background is its elevation (this because the card is compatible with all Android versions before Lollipop, which don't have the elevation property). Use setCardBackgroundColor to set a background color (or app:cardBackgroundColor in your xml).

If you need a background image, rather than a color, place an ImageView inside of your card as this answer suggests.

Do what you want, but DON'T call any setBackground... method on the CardView, or you will lose the card shadow (its elevation effect).

Secondly, to animate your elevation use the following code:

ObjectAnimator animator = ObjectAnimator.ofFloat(cardView, "cardElevation", start, end);
// if needed set duration, interpolator, or what you want on the animator
animator.start();