2

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?

Vancore
  • 657
  • 1
  • 9
  • 18

3 Answers3

10

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();
Community
  • 1
  • 1
Massimo
  • 3,436
  • 4
  • 40
  • 68
  • Does your card is contained inside of another layout? The elevation shadow could simply be not visible because of the `clipChildren` and `clipToPadding` properties of the container layout (which are `true` by default). – Massimo Feb 22 '17 at 15:45
  • I updated the answer. Your code has some problem related to a wrong usage of `View`'s methods. – Massimo Feb 22 '17 at 15:55
  • My cardView was indeed inside a RelativeLayout. I deleted the parent RelativeLayout, since my cardView is a row item of the recyclerView, but still no changes. Problem is that i cannot simply use a backgroundColor, because i want to have specific background (with only a red line on the right side) – Vancore Feb 22 '17 at 15:56
  • 2
    `CardView` is an extension of `FrameLayout`: so place an `ImageView` as first son of the card and put your background as `src` of this ImageView (eventually with a right `scaleType`). http://stackoverflow.com/a/33920684/1507512 – Massimo Feb 22 '17 at 15:58
  • I updated the answer to explain how to animate the elevation correctly when the card view is clicked – Massimo Feb 22 '17 at 16:05
  • The approach with the ImageView as first child seems to work, although I have some layoutGravity problems (but this is probably another problem) – Vancore Feb 22 '17 at 16:18
1

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"
Atef Hares
  • 4,715
  • 3
  • 29
  • 61
1

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.

Gabriel Feo
  • 73
  • 1
  • 6
  • Welcome to SO! Please, try to explain a little bit your answer. Answers with just a few words and some links should be added as comments not answers. – David García Bodego Oct 19 '19 at 03:29