| page.title=Defining Custom Animations | |
| @jd:body | |
| <div id="tb-wrapper"> | |
| <div id="tb"> | |
| <h2>This lesson teaches you to</h2> | |
| <ol> | |
| <li><a href="#Touch">Customize Touch Feedback</a></li> | |
| <li><a href="#Reveal">Use the Reveal Effect</a></li> | |
| <li><a href="#Transitions">Customize Activity Transitions</a></li> | |
| <li><a href="#ViewState">Animate View State Changes</a></li> | |
| <li><a href="#AnimVector">Animate Vector Drawables</a></li> | |
| </ol> | |
| <h2>You should also read</h2> | |
| <ul> | |
| <li><a href="http://www.google.com/design/spec">Material design specification</a></li> | |
| <li><a href="{@docRoot}design/material/index.html">Material design on Android</a></li> | |
| </ul> | |
| </div> | |
| </div> | |
| <p>Animations in material design give users feedback on their actions and provide visual | |
| continuity as users interact with your app. The material theme provides some default animations | |
| for buttons and activity transitions, and Android 5.0 (API level 21) and above lets you customize | |
| these animations and create new ones:</p> | |
| <ul> | |
| <li>Touch feedback</li> | |
| <li>Circular Reveal</li> | |
| <li>Activity transitions</li> | |
| <li>Curved motion</li> | |
| <li>View state changes</li> | |
| </ul> | |
| <h2 id="Touch">Customize Touch Feedback</h2> | |
| <p>Touch feedback in material design provides an instantaneous visual confirmation at the | |
| point of contact when users interact with UI elements. The default touch feedback animations | |
| for buttons use the new {@link android.graphics.drawable.RippleDrawable} class, which transitions | |
| between different states with a ripple effect.</p> | |
| <p>In most cases, you should apply this functionality in your view XML by specifying the view | |
| background as:</p> | |
| <ul> | |
| <li><code>?android:attr/selectableItemBackground</code> for a bounded ripple.</li> | |
| <li><code>?android:attr/selectableItemBackgroundBorderless</code> for a ripple that extends beyond | |
| the view. It will be drawn upon, and bounded by, the nearest parent of the view with a non-null | |
| background.</li> | |
| </ul> | |
| <p class="note"><strong>Note:</strong> <code>selectableItemBackgroundBorderless</code> is a new | |
| attribute introduced in API level 21.</p> | |
| <p>Alternatively, you can define a {@link android.graphics.drawable.RippleDrawable} | |
| as an XML resource using the <code>ripple</code> element.</p> | |
| <p>You can assign a color to {@link android.graphics.drawable.RippleDrawable} objects. To change | |
| the default touch feedback color, use the theme's <code>android:colorControlHighlight</code> | |
| attribute.</p> | |
| <p>For more information, see the API reference for the {@link | |
| android.graphics.drawable.RippleDrawable} class.</p> | |
| <h2 id="Reveal">Use the Reveal Effect</h2> | |
| <p>Reveal animations provide users visual continuity when you show or hide a group of UI | |
| elements. The {@link android.view.ViewAnimationUtils#createCircularReveal | |
| ViewAnimationUtils.createCircularReveal()} method enables you to animate a clipping circle to | |
| reveal or hide a view.</p> | |
| <p>To reveal a previously invisible view using this effect:</p> | |
| <pre> | |
| // previously invisible view | |
| View myView = findViewById(R.id.my_view); | |
| // get the center for the clipping circle | |
| int cx = myView.getWidth() / 2; | |
| int cy = myView.getHeight() / 2; | |
| // get the final radius for the clipping circle | |
| float finalRadius = (float) Math.hypot(cx, cy); | |
| // create the animator for this view (the start radius is zero) | |
| Animator anim = | |
| ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); | |
| // make the view visible and start the animation | |
| myView.setVisibility(View.VISIBLE); | |
| anim.start(); | |
| </pre> | |
| <p>To hide a previously visible view using this effect:</p> | |
| <pre> | |
| // previously visible view | |
| final View myView = findViewById(R.id.my_view); | |
| // get the center for the clipping circle | |
| int cx = myView.getWidth() / 2; | |
| int cy = myView.getHeight() / 2; | |
| // get the initial radius for the clipping circle | |
| float initialRadius = (float) Math.hypot(cx, cy); | |
| // create the animation (the final radius is zero) | |
| Animator anim = | |
| ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0); | |
| // make the view invisible when the animation is done | |
| anim.addListener(new AnimatorListenerAdapter() { | |
| @Override | |
| public void onAnimationEnd(Animator animation) { | |
| super.onAnimationEnd(animation); | |
| myView.setVisibility(View.INVISIBLE); | |
| } | |
| }); | |
| // start the animation | |
| anim.start(); | |
| </pre> | |
| <h2 id="Transitions">Customize Activity Transitions</h2> | |
| <!-- shared transition video --> | |
| <div style="width:290px;margin-left:35px;float:right"> | |
| <div class="framed-nexus5-port-span-5"> | |
| <video class="play-on-hover" autoplay=""> | |
| <source src="{@docRoot}design/material/videos/ContactsAnim.mp4"> | |
| <source src="{@docRoot}design/material/videos/ContactsAnim.webm"> | |
| <source src="{@docRoot}design/material/videos/ContactsAnim.ogv"> | |
| </video> | |
| </div> | |
| <div style="font-size:10pt;margin-left:20px;margin-bottom:30px"> | |
| <p class="img-caption" style="margin-top:3px;margin-bottom:10px"><strong>Figure 1</strong> - A | |
| transition with shared elements.</p> | |
| <em>To replay the movie, click on the device screen</em> | |
| </div> | |
| </div> | |
| <p>Activity transitions in material design apps provide visual connections between different states | |
| through motion and transformations between common elements. You can specify custom animations for | |
| enter and exit transitions and for transitions of shared elements between activities.</p> | |
| <ul> | |
| <li>An <strong>enter</strong> transition determines how views in an activity enter the scene. | |
| For example, in the <em>explode</em> enter transition, the views enter the scene from the outside | |
| and fly in towards the center of the screen.</li> | |
| <li>An <strong>exit</strong> transition determines how views in an activity exit the scene. For | |
| example, in the <em>explode</em> exit transition, the views exit the scene away from the | |
| center.</li> | |
| <li>A <strong>shared elements</strong> transition determines how views that are shared between | |
| two activities transition between these activities. For example, if two activities have the same | |
| image in different positions and sizes, the <em>changeImageTransform</em> shared element transition | |
| translates and scales the image smoothly between these activities.</li> | |
| </ul> | |
| <p>Android 5.0 (API level 21) supports these enter and exit transitions:</p> | |
| <ul> | |
| <li><em>explode</em> - Moves views in or out from the center of the scene.</li> | |
| <li><em>slide</em> - Moves views in or out from one of the edges of the scene.</li> | |
| <li><em>fade</em> - Adds or removes a view from the scene by changing its opacity.</li> | |
| </ul> | |
| <p>Any transition that extends the {@link android.transition.Visibility} class is supported | |
| as an enter or exit transition. For more information, see the API reference for the | |
| {@link android.transition.Transition} class.</p> | |
| <p>Android 5.0 (API level 21) also supports these shared elements transitions:</p> | |
| <ul> | |
| <li><em>changeBounds</em> - Animates the changes in layout bounds of target views.</li> | |
| <li><em>changeClipBounds</em> - Animates the changes in clip bounds of target views.</li> | |
| <li><em>changeTransform</em> - Animates the changes in scale and rotation of target views.</li> | |
| <li><em>changeImageTransform</em> - Animates changes in size and scale of target images.</li> | |
| </ul> | |
| <p>When you enable activity transitions in your app, the default cross-fading transition is | |
| activated between the entering and exiting activities.</p> | |
| <img src="{@docRoot}training/material/images/SceneTransition.png" alt="" width="600" height="405" | |
| style="margin-top:20px"/> | |
| <p class="img-caption"> | |
| <strong>Figure 2</strong> - A scene transition with one shared element. | |
| </p> | |
| <h3 id="custom-trans">Specify custom transitions</h3> | |
| <p>First, enable window content transitions with the <code>android:windowActivityTransitions</code> | |
| attribute when you define a style that inherits from the material theme. You can also specify | |
| enter, exit, and shared element transitions in your style definition:</p> | |
| <pre> | |
| <style name="BaseAppTheme" parent="android:Theme.Material"> | |
| <!-- enable window content transitions --> | |
| <item name="android:windowActivityTransitions">true</item> | |
| <!-- specify enter and exit transitions --> | |
| <item name="android:windowEnterTransition">@transition/explode</item> | |
| <item name="android:windowExitTransition">@transition/explode</item> | |
| <!-- specify shared element transitions --> | |
| <item name="android:windowSharedElementEnterTransition"> | |
| @transition/change_image_transform</item> | |
| <item name="android:windowSharedElementExitTransition"> | |
| @transition/change_image_transform</item> | |
| </style> | |
| </pre> | |
| <p>The <code>change_image_transform</code> transition in this example is defined as follows:</p> | |
| <pre> | |
| <!-- res/transition/change_image_transform.xml --> | |
| <!-- (see also Shared Transitions below) --> | |
| <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> | |
| <changeImageTransform/> | |
| </transitionSet> | |
| </pre> | |
| <p>The <code>changeImageTransform</code> element corresponds to the | |
| {@link android.transition.ChangeImageTransform} class. For more information, see the API | |
| reference for {@link android.transition.Transition}.</p> | |
| <p>To enable window content transitions in your code instead, call the | |
| {@link android.view.Window#requestFeature Window.requestFeature()} method:</p> | |
| <pre> | |
| // inside your activity (if you did not enable transitions in your theme) | |
| getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); | |
| // set an exit transition | |
| getWindow().setExitTransition(new Explode()); | |
| </pre> | |
| <p>To specify transitions in your code, call these methods with a {@link | |
| android.transition.Transition} object:</p> | |
| <ul> | |
| <li>{@link android.view.Window#setEnterTransition Window.setEnterTransition()}</li> | |
| <li>{@link android.view.Window#setExitTransition Window.setExitTransition()}</li> | |
| <li>{@link android.view.Window#setSharedElementEnterTransition | |
| Window.setSharedElementEnterTransition()}</li> | |
| <li>{@link android.view.Window#setSharedElementExitTransition | |
| Window.setSharedElementExitTransition()}</li> | |
| </ul> | |
| <p>The {@link android.view.Window#setExitTransition setExitTransition()} and {@link | |
| android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} methods define | |
| the exit transition for the calling activity. The {@link android.view.Window#setEnterTransition | |
| setEnterTransition()} and {@link android.view.Window#setSharedElementEnterTransition | |
| setSharedElementEnterTransition()} methods define the enter transition for the called activity.</p> | |
| <p>To get the full effect of a transition, you must enable window content transitions on both the | |
| calling and called activities. Otherwise, the calling activity will start the exit transition, | |
| but then you'll see a window transition (like scale or fade).</p> | |
| <p>To start an enter transition as soon as possible, use the | |
| {@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()} | |
| method on the called activity. This lets you have more dramatic enter transitions.</p> | |
| <h3>Start an activity using transitions</h3> | |
| <p>If you enable transitions and set an exit transition for an activity, the transition is activated | |
| when you launch another activity as follows:</p> | |
| <pre> | |
| startActivity(intent, | |
| ActivityOptions.makeSceneTransitionAnimation(this).toBundle()); | |
| </pre> | |
| <p>If you have set an enter transition for the second activity, the transition is also activated | |
| when the activity starts. To disable transitions when you start another activity, provide | |
| a <code>null</code> options bundle.</p> | |
| <h3>Start an activity with a shared element</h3> | |
| <p>To make a screen transition animation between two activities that have a shared element:</p> | |
| <ol> | |
| <li>Enable window content transitions in your theme.</li> | |
| <li>Specify a shared elements transition in your style.</li> | |
| <li>Define your transition as an XML resource.</li> | |
| <li>Assign a common name to the shared elements in both layouts with the | |
| <code>android:transitionName</code> attribute.</li> | |
| <li>Use the {@link android.app.ActivityOptions#makeSceneTransitionAnimation | |
| ActivityOptions.makeSceneTransitionAnimation()} method.</li> | |
| </ol> | |
| <pre> | |
| // get the element that receives the click event | |
| final View imgContainerView = findViewById(R.id.img_container); | |
| // get the common element for the transition in this activity | |
| final View androidRobotView = findViewById(R.id.image_small); | |
| // define a click listener | |
| imgContainerView.setOnClickListener(new View.OnClickListener() { | |
| @Override | |
| public void onClick(View view) { | |
| Intent intent = new Intent(this, Activity2.class); | |
| // create the transition animation - the images in the layouts | |
| // of both activities are defined with android:transitionName="robot" | |
| ActivityOptions options = ActivityOptions | |
| .makeSceneTransitionAnimation(this, androidRobotView, "robot"); | |
| // start the new activity | |
| startActivity(intent, options.toBundle()); | |
| } | |
| }); | |
| </pre> | |
| <p>For shared dynamic views that you generate in your code, use the | |
| {@link android.view.View#setTransitionName View.setTransitionName()} method to specify a common | |
| element name in both activities.</p> | |
| <p>To reverse the scene transition animation when you finish the second activity, call the | |
| {@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()} | |
| method instead of {@link android.app.Activity#finish Activity.finish()}.</p> | |
| <h3>Start an activity with multiple shared elements</h3> | |
| <p>To make a scene transition animation between two activities that have more than one shared | |
| element, define the shared elements in both layouts with the <code>android:transitionName</code> | |
| attribute (or use the {@link android.view.View#setTransitionName View.setTransitionName()} method | |
| in both activities), and create an {@link android.app.ActivityOptions} object as follows:</p> | |
| <pre> | |
| ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, | |
| Pair.create(view1, "agreedName1"), | |
| Pair.create(view2, "agreedName2")); | |
| </pre> | |
| <h2 id="CurvedMotion">Use Curved Motion</h2> | |
| <p>Animations in material design rely on curves for time interpolation and spatial movement | |
| patterns. With Android 5.0 (API level 21) and above, you can define custom timing curves and | |
| curved motion patterns for animations.</p> | |
| <p>The {@link android.view.animation.PathInterpolator} class is a new interpolator based on a | |
| Bézier curve or a {@link android.graphics.Path} object. This interpolator specifies a motion curve | |
| in a 1x1 square, with anchor points at (0,0) and (1,1) and control points as specified using the | |
| constructor arguments. You can also define a path interpolator as an XML resource:</p> | |
| <pre> | |
| <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" | |
| android:controlX1="0.4" | |
| android:controlY1="0" | |
| android:controlX2="1" | |
| android:controlY2="1"/> | |
| </pre> | |
| <p>The system provides XML resources for the three basic curves in the material design | |
| specification:</p> | |
| <ul> | |
| <li><code>@interpolator/fast_out_linear_in.xml</code></li> | |
| <li><code>@interpolator/fast_out_slow_in.xml</code></li> | |
| <li><code>@interpolator/linear_out_slow_in.xml</code></li> | |
| </ul> | |
| <p>You can pass a {@link android.view.animation.PathInterpolator} object to the {@link | |
| android.animation.Animator#setInterpolator Animator.setInterpolator()} method.</p> | |
| <p>The {@link android.animation.ObjectAnimator} class has new constructors that enable you to animate | |
| coordinates along a path using two or more properties at once. For example, the following animator | |
| uses a {@link android.graphics.Path} object to animate the X and Y properties of a view:</p> | |
| <pre> | |
| ObjectAnimator mAnimator; | |
| mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); | |
| ... | |
| mAnimator.start(); | |
| </pre> | |
| <h2 id="ViewState">Animate View State Changes</h2> | |
| <p>The {@link android.animation.StateListAnimator} class lets you define animators that run when | |
| the state of a view changes. The following example shows how to define an {@link | |
| android.animation.StateListAnimator} as an XML resource:</p> | |
| <pre> | |
| <!-- animate the translationZ property of a view when pressed --> | |
| <selector xmlns:android="http://schemas.android.com/apk/res/android"> | |
| <item android:state_pressed="true"> | |
| <set> | |
| <objectAnimator android:propertyName="translationZ" | |
| android:duration="@android:integer/config_shortAnimTime" | |
| android:valueTo="2dp" | |
| android:valueType="floatType"/> | |
| <!-- you could have other objectAnimator elements | |
| here for "x" and "y", or other properties --> | |
| </set> | |
| </item> | |
| <item android:state_enabled="true" | |
| android:state_pressed="false" | |
| android:state_focused="true"> | |
| <set> | |
| <objectAnimator android:propertyName="translationZ" | |
| android:duration="100" | |
| android:valueTo="0" | |
| android:valueType="floatType"/> | |
| </set> | |
| </item> | |
| </selector> | |
| </pre> | |
| <p> | |
| To attach custom view state animations to a view, define an animator using | |
| the <code>selector</code> element in an XML resource file as in this example, | |
| and assign it to your view with the <code>android:stateListAnimator</code> | |
| attribute. To assign a state list animator to a view in your code, use the | |
| {@link android.animation.AnimatorInflater#loadStateListAnimator | |
| AnimatorInflater.loadStateListAnimator()} method, and assign the animator to | |
| your view with the {@link android.view.View#setStateListAnimator | |
| View.setStateListAnimator()} method. | |
| </p> | |
| <p>When your theme extends the material theme, buttons have a Z animation by default. To avoid this | |
| behavior in your buttons, set the <code>android:stateListAnimator</code> attribute to | |
| <code>@null</code>.</p> | |
| <p>The {@link android.graphics.drawable.AnimatedStateListDrawable} class lets you create drawables | |
| that show animations between state changes of the associated view. Some of the system widgets in | |
| Android 5.0 use these animations by default. The following example shows how | |
| to define an {@link android.graphics.drawable.AnimatedStateListDrawable} as an XML resource:</p> | |
| <pre> | |
| <!-- res/drawable/myanimstatedrawable.xml --> | |
| <animated-selector | |
| xmlns:android="http://schemas.android.com/apk/res/android"> | |
| <!-- provide a different drawable for each state--> | |
| <item android:id="@+id/pressed" android:drawable="@drawable/drawableP" | |
| android:state_pressed="true"/> | |
| <item android:id="@+id/focused" android:drawable="@drawable/drawableF" | |
| android:state_focused="true"/> | |
| <item android:id="@id/default" | |
| android:drawable="@drawable/drawableD"/> | |
| <!-- specify a transition --> | |
| <transition android:fromId="@+id/default" android:toId="@+id/pressed"> | |
| <animation-list> | |
| <item android:duration="15" android:drawable="@drawable/dt1"/> | |
| <item android:duration="15" android:drawable="@drawable/dt2"/> | |
| ... | |
| </animation-list> | |
| </transition> | |
| ... | |
| </animated-selector> | |
| </pre> | |
| <h2 id="AnimVector">Animate Vector Drawables</h2> | |
| <p><a href="{@docRoot}training/material/drawables.html#VectorDrawables">Vector Drawables</a> are | |
| scalable without losing definition. The {@link android.graphics.drawable.AnimatedVectorDrawable} | |
| class lets you animate the properties of a vector drawable.</p> | |
| <p>You normally define animated vector drawables in three XML files:</p> | |
| <ul> | |
| <li>A vector drawable with the <code><vector></code> element in | |
| <code>res/drawable/</code></li> | |
| <li>An animated vector drawable with the <code><animated-vector></code> element in | |
| <code>res/drawable/</code></li> | |
| <li>One or more object animators with the <code><objectAnimator></code> element in | |
| <code>res/anim/</code></li> | |
| </ul> | |
| <p>Animated vector drawables can animate the attributes of the <code><group></code> and | |
| <code><path></code> elements. The <code><group></code> elements defines a set of | |
| paths or subgroups, and the <code><path></code> element defines paths to be drawn.</p> | |
| <p>When you define a vector drawable that you want to animate, use the <code>android:name</code> | |
| attribute to assign a unique name to groups and paths, so you can refer to them from your animator | |
| definitions. For example:</p> | |
| <pre> | |
| <!-- res/drawable/vectordrawable.xml --> | |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |
| android:height="64dp" | |
| android:width="64dp" | |
| android:viewportHeight="600" | |
| android:viewportWidth="600"> | |
| <group | |
| <strong>android:name="rotationGroup"</strong> | |
| android:pivotX="300.0" | |
| android:pivotY="300.0" | |
| android:rotation="45.0" > | |
| <path | |
| <strong>android:name="v"</strong> | |
| android:fillColor="#000000" | |
| android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> | |
| </group> | |
| </vector> | |
| </pre> | |
| <p>The animated vector drawable definition refers to the groups and paths in the vector drawable | |
| by their names:</p> | |
| <pre> | |
| <!-- res/drawable/animvectordrawable.xml --> | |
| <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" | |
| android:drawable="@drawable/vectordrawable" > | |
| <target | |
| android:name="rotationGroup" | |
| android:animation="@anim/rotation" /> | |
| <target | |
| android:name="v" | |
| android:animation="@anim/path_morph" /> | |
| </animated-vector> | |
| </pre> | |
| <p>The animation definitions represent {@link android.animation.ObjectAnimator} or {@link | |
| android.animation.AnimatorSet} objects. The first animator in this example rotates the target | |
| group 360 degrees:</p> | |
| <pre> | |
| <!-- res/anim/rotation.xml --> | |
| <objectAnimator | |
| android:duration="6000" | |
| android:propertyName="rotation" | |
| android:valueFrom="0" | |
| android:valueTo="360" /> | |
| </pre> | |
| <p>The second animator in this example morphs the vector drawable's path from one shape to | |
| another. Both paths must be compatible for morphing: they must have the same number of commands | |
| and the same number of parameters for each command.</p> | |
| <pre> | |
| <!-- res/anim/path_morph.xml --> | |
| <set xmlns:android="http://schemas.android.com/apk/res/android"> | |
| <objectAnimator | |
| android:duration="3000" | |
| android:propertyName="pathData" | |
| android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" | |
| android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" | |
| android:valueType="pathType" /> | |
| </set> | |
| </pre> | |
| <p>For more information, see the API reference for {@link | |
| android.graphics.drawable.AnimatedVectorDrawable}.</p> |