--- 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); } ```