Vancore
Vancore

Reputation: 697

Setting CardView elevation programmatically

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?

Upvotes: 2

Views: 11567

Answers (3)

Gabriel Feo
Gabriel Feo

Reputation: 73

The View's Outline is what "drives the shape of its shadows". When changing the background implicitly changes the view's outline, you must explicitly invalidate the outline by calling View.invalidateOutline(), for the shadows to be redrawn around the view.

Upvotes: 1

Massimo Milazzo
Massimo Milazzo

Reputation: 3531

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();

Upvotes: 10

Atef Hares
Atef Hares

Reputation: 4891

try to use

cardview.setMaxCardElevation();

but note that:

Calling this method has no effect if device OS version is Lollipop or newer and getUseCompatPadding() is false.

Or try

cardview.setCardElevation();

Source

Or from xml:

Add android:clipChildren="false" to the parent of your cardview or add a small amount of padding to your View and set android:clipToPadding="false"

and use

card_view:cardElevation="VALUE"

Upvotes: 1

Related Questions