How to add a flashing border to CardView
Feb 17, 2020 · 4 min read
Recently we got the task from our UX people to add a “flashing border animation” to our CardViews when you press them. The border should shortly become another color and then go back to its original state.
To this date, animations in Android are still kinda a black box to me. My team estimated the ticket rather high, because we all knew it’s somehow going to work with animations, but no one really had an idea how to start. As every dev out there the first thing I did, when grabbing the ticket, was googling for similar problems, but animating a flashing border seemed to be the problem of no one else out there…
Many answers on StackOverflow were setting a custom background on a View and then animated the change of a background drawable . However, I was afraid I then have to manually take care of the Ripple effect, or even worse the CardView is going to look crappy. After few more answers I got reminded that the new MaterialCardView has a property strokeColor . So animating the strokeColor from some value to another one could work.
Android has a built in to animate color changes of view properties, we can simply use ObjectAnimator.ofArgb() for this case:
Saying we want to animate the property strokeColor of our cardView to value Color.RED over a duration of one second. You can pass multiple color values, as it takes a vararg . Passing one will animate from current value to the given value. Passing two will animate from first to second argument and passing more will animate to all of them.
However, if we put above code in a click listener of our cardView , we see..strange behaviour:
The first animation we start does.. nothing and the second instantly colors or border red. I was wondering a while why the color is not changing, then I added an update listener, which emits every new value of the animation:
So the color is actually changing from white to red (read it as “red, green, blue, alpha”), but it’s just not updating the view! Changing our update listener to
Ha! Slowly changing to red now. First step done ✅
As we want to have a flashing border, we now need to reverse the stroke color to its initial value. Luckily there’s already a reverse() function on those animators, so we can just put:
Saying at the end of the animation, reverse the animation. However, after the reverse animation is done, the listener will be triggered again, and reverse the reverse, after which it’s triggered again, and will reverse the reversed reverse.. well you understand 😄 it’s now an infinite animation.
What we can do is not use the extension function, add our own listener and remove it again, so it cannot be triggered again:
This doesn’t play it infinitely anymore, but after the reversion it plays the initial animation again 🤦♂ I didn’t understand why this is happening — if you know, you’re open to leave a comment.
At this point I just extracted everything to a method and started another animation after the first one ended:
which looks like this:
Important: to see any stroke color at all, you have to give your CardView a strokeWidth of at least 1dp . I also advise to set strokeColor initially to Color.TRANSPARENT , otherwise you may get an unwanted border.
I hope this article helped you achieving something similar and saved you some googling time that I already spent 😉
Источник