-
Jennifer Mankoff authored
with simplified text and removal of most cse340 specific information
Jennifer Mankoff authoredwith simplified text and removal of most cse340 specific information
animation.html 8.44 KiB
---
layout: presentation
title: Animation Slides
description: How to do animation in android
class: middle, center, inverse
---
# Interaction Programming Lab (Spring 2020)
## Week 1: How to do Animation in Android
.title-slide-logo[

]
---
## Animation on Android

- Different Animation Systems
- _Property Animation_ - preferred method; more flexible
- _View Animation_ - simple setup; the old way (basically xml definitions x_x)
- _Drawable Animation_ - load `Drawable` resources and display them one frame after the other (like a gif)
---
## Property Animation
- Define an animate that changes on object's property (a field on a object) over a length of time
.center[

]
---
## Property Animation
- Animation Characteristics
- _Duration_ - length of the animation (default is 300 ms)
- _Time Interpolation_ - how the values are calculated as a function of the current elapsed time
- _Repeat Count & Behavior_ - # of times to repeat and whether to restart or play in reverse, etc.
- _Animator Sets_ - can group a set of animations into a logical set and play simultaneously or after delays
- _Frame Refresh Delay_ - how often to refresh the frames of your animation (default is 10 ms) but **depends on how busy the system is**
---
## Property Animation
- Process of how an animation is calculated:
.center[

]
---
## `ValueAnimator`
- Keeps track of the animation's timing (how long its been running and current value of property)
- Contains a `TimeInterpolator` that defines the type of interpolation for the value over time
- Contains a `TypeEvaluator` that figures out how to calculate values for the property being animated
```java
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
// Starts the animation
animation.start();
// TODO: need to listen for updates to get the returned value
```
---
## `ObjectAnimator`
- Rather than listening for a value, we can simply directly animate a property on an object
- **However**: the property that you are animating must have a setter function (in camel case) in the form of set<propertyName>() for this to work
```java
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();
```
---
## Animation Listeners (1/2)
- `Animator.AnimatorListener`
- `onAnimationStart()` - Called when the animation starts.
- `onAnimationEnd()` - Called when the animation ends.
- `onAnimationRepeat()` - Called when the animation repeats itself.
- `onAnimationCancel()` - Called when the animation is canceled.
- **Note**: A cancelled animation also calls - `onAnimationEnd()`, regardless of how the animation were ended.
- `ValueAnimator.AnimatorUpdateListener`
- `onAnimationUpdate()` - called on every frame of the animation. Listen to this event to use the calculated values generated by `ValueAnimator` during an animation.
---
## Animation Listeners (2/2)
- Example using `onAnimationEnd`:
```java
// Create a fade animation that changes the alpha of an object
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
// Set duration to be 250 ms
fadeAnim.setDuration(250);
// Add a listeners to the fade anim
fadeAnim.addListener(new AnimatorListenerAdapter() {
// When the animation finishes remove the object from the list of balls
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
});
```
---
## Multiple Simultaneous Animations
- `AnimatorSet`
```java
// Create animator set
AnimatorSet bouncer = new AnimatorSet();
// Add the good stuff
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
// Animate the alpha value from 1->0
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
// Build up a another level of animation sets
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
// Starts the animations
animatorSet.start()
```
---
## There's more flexilbity... (1/3)
- You can specify `Keyframe` objects0 and to control the animation
```java
// Key for start at 0
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
// Key for half way finished animation
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
// Key for end state
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
// ValueName-to-keyframes
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe(
"rotation",
kf0,
kf1,
kf2);
// Create the animation
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(
target,
pvhRotation)
rotationAnim.setDuration(5000ms);
```
---
## There's more flexibility... (2/3)
- You can declare animations in XML files:
```xml
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
```
---
## There's more flexibility... (3/3)
- You can then run the animation by doing the following:
```java
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();
```
- Note that animations xml files should be in the `res/anim/` directory
---
## What About Animating Views? (1/2)
- Steamlined process for view animation
- `View` auto-magically calls `invalidate()` when their properties are changed
- This is useful when using the `ObjectAnimator` class
---
## What About Animating Views? (2/2)
- If you want to animate a view, you need only specify one of the magic the property of the `View` class
- `translationX` /`translationY` - view location as a delta from its top/left coordinates relative to the parent
- `rotation` / `rotationX`/`rotationY` - control 2D rotation and 3D rotation around a pivot point
- `scaleX` / `scaleY` - 2D scaliong of a `View` around a pivot point
- `pivotX` / `pivotY` - changes location of thej pivot point (default is object's center)
- `x` / `y` - utility property to describe the final location of a `View` in its container as a sum of (left, top) + `translationX`, `translationY`)
- `alpha`
---
## Drawable Animation (1/4)
- Way of loading a series of `Drawable` resouces one after the other to create an Animation
- Similar to a gif or stop-motion animation style
- `AnimationDrawable` is the basis for `Drawable` animations
---
## Drawable Animation (2/4)
- Define the frames of your animation in an XML file that list the frames in order
- The example below is a 3 frame animation that
- To play once and hold the last frame at the end set `android:oneshot=true`
- If it is false, the animation will loop indefinitely
```xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
<item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
<item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>
```
---
## Drawable Animation (3/4)
- Now use the animation in code
```java
// Variable to hold the animation
AnimationDrawable mRocketAnimation;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Grab the imageview and set the image drawable for the animation
ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
mRocketAnimation = (AnimationDrawable) rocketImage.getBackground();
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// Start the animation on touch
mRocketAnimation.start();
return true;
}
return super.onTouchEvent(event);
}
```