[MUSIC PLAYING]
DANIEL OLSHANSKY: Hi.
My name is Daniel Olshansky.
I'm Chet's intern here on the Android Team at Google.
And today, I'll be discussing a few card flip innovations.
So today, I'll just show you how to flip cards, both from
side to side, out and in, as well as a few little tricks on
how to do graphic animations on darkening and spinning the
cards when you need to.
The main trick to today's animation is going to be the
fact that, after every single animation, we're going to
update the Layer parameters such that future animations
are not going to be dependent on the values of previous
animations.
So we'll be animating the properties.
But then, at the end of every single animation, we'll be
setting them all back to zero, such that any future
animations won't be dependent on what has been done before.
So going straight into the demo, here, we have a
stack of red cards.
I can use touch events to flip it from right to left.
Similarly, they can flip it from left to right.
The speed at which this animates is actually dependent
on the speed at which you fling it.
You can also swipe down to open a stack of cards or swipe
back up to close a stack of cards, place both stacks.
Or if you tap on a stack, then there's a little delayed
animation showing you how to rotate a full stack of cards
completely.
So jumping straight into the code, there is a lot of
boilerplate code that you can look into where you handle all
the touches, determine which way I'm flinging
and things like that.
But the interesting things happen here in Card View.
So scrolling down, initially, one of the things you need to
note is that Views, and in turn Image Views, have this
property called Set Camera Distance.
So what this actually lets you do is set the position along
the Zed-axis of how far you want to be
from the actual animation.
Originally, in this animation, if you were to set it back to
its default value, you would see that we don't actually see
the flip animation, because it happens behind the screen.
After that, we retrieved the bitmaps that we used for the
front and the back of the cards.
And keep going down.
Here, this is important to note.
What we're doing to the bitmap drawable is adding a one-pixel
transparent border.
And the reason we're doing this is, when you're rotating
a rectangle within some view, the edges don't actually have
any values that they can retrieve outside the
boundaries of the rectangle.
So you end up getting these very jagged edges when you
rotate a rectangle.
But this problem can be very easily [? abided ?], simply by
having a one-pixel transparent border.
And it's done right here.
And then you will see that the edges are actually smooth as
you rotate the cards.
Then there's two methods, flip from left to right, and flip
from right to left.
Before we actually call the flipping animation, we need to
set the pivot.
By default, the x and y pivots of all views are along center.
So if you were to rotate it, it would only
rotate about its center.
But setting these manually would give us more precision
as to how we want to animate it.
Then there's a method called flip horizontally, after we
set the pivot.
What this does is set up a lot of use property values hold,
or object animators, and things like that to actually
animate the rotation of it along the
y-axis by 180 degrees.
We also added translation animation such that, when it
finishes animating, it's in the correct offset within the
corresponding pile that it animated to.
And what we're also doing is adding an update listener such
that, as it's animating, we need to make sure when it
reached the halfway point.
And at the halfway point, we want to switch the drawable
from the red bitmap to the blue bitmap, or the other way
around, because it's on the other side now.
Going down farther more, I'm setting up a few key frame
animations on a property called Shadow.
This is a custom property used to darken the image as it's
animating, which I'll show you in a second.
Scrolling down even more, I set a duration using the
velocity passed in from the fling, and then use an
animator set to play all of these together.
At the end of the animation, I need to update the bitmaps and
set some default values back to their default values.
So like I said, I'm animating a custom
property called Shadow.
So since my string is Shadow, my Object Animator is going to
look for a property on that target called Set
Shadow right here.
And all I'm doing here is using alpha blending imported
off mode multiply.
And all this does is just darken the
image, as it's animating.
And that's how you get that shadow-like effect.
Toggle front shown, simply switches the
red and blue bitmaps.
That switches the flag determining which bitmap
you're using.
And there's some more very simple boilerplate code to do
some set up things here as well.
So the thing is a non-draw.
When I'm flipping my card, instead of actually creating a
new bitmap that's horizontally mirrored from my original
bitmap, all I'm really doing is concatenating my canvas
with a matrix that does that exact same thing.
So this way, it's a lot more efficient.
It doesn't use as much memory.
It uses the exact same bitmap.
But I'm still able to achieve that horizontal mirroring
effect of the image after I've actually flipped it.
And the reason I need to do that is because in Update
Layer Parameters, I set the rotation x and y back to zero.
That's what I'm trying to do here.
I'm trying to make any future animations be independent of
what they were before.
But in order to achieve that, I also need to update the left
margin of my Layer parameters to be exactly where it is
after the animation, and then, of course, update the
parameters as well.
So this, in conjunction with customizing the canvas when I
need to lets me achieve this whole independence effect
after every single animation.
Again, some simple code to offset it where I need to,
switch the bitmaps.
So here's the code for rotating the actual card.
What this does is determine what angle I should rotate it
by, depending on how far the card is down the stack.
And then I simply return Object Animator that rotates
that view by that angle.
The other thing that I can also do is when I tap on a
card and all the cards flip in a circle with a certain delay
between them, it's almost the same animation, except the
angle is always 360 degrees.
But the other thing to note is that you need a start delay.
The cards on the tops are animating almost immediately,
whereas, the cards underneath only start animating when all
the cards above that card have already gone past a certain
point in the animation.
So I add a different start delay, depending
on where card is.
And then I play all those animations together.
So that's how you actually get the animations for every
individual card.
And if you look in the card [INAUDIBLE] activity, which is
the main activity, all I'm doing here is looping through
all my cards when some stack has been tapped.
I'd retrieve that Object Animator that I can get from
my Card View.
And the other thing I'm doing is bringing that
child to the front.
So depending on how they're flipping the cards, I don't
exactly know whether all the cards on the right stack are
on top of the cards on the left stack.
So I'm just sequentially calling bring child to front,
to change the set order of all the cards in the stack that
I'm animating.
And the other thing you need to do is always call request
layout after you've called bring child to front, in order
for that change to take effect.
Otherwise, you'll have to wait for the child to be brought to
front until somebody has requested a
layout on your view.
Very similarly, in order to achieve the full card
rotation, I am retrieving the Object Animators from all the
cards, bringing the objects to the front, and doing almost
the exact same thing, except with a different Object
Animator, which I can retrieve from my Card View.
So that's pretty much how you can flip cards, rotate them,
and animate them in different ways.
Thanks.