材料设计中的动画对用户的操作给予了反馈,并且在与应用交互时提供了持续的可见性。材料主题提供了一些按钮动画和活动过渡,Android 5.0允许你自定义动画并且可以创建新的动画:
自定义触摸反馈
在用户与UI元素交互时,从接触的角度来看,材料设计中的触摸反馈提供了瞬间的视觉确认。按钮的默认触摸动画使用了新的RippleDrawable
类,使得按钮采用涟漪效果在不同的状态之间过渡。
在大多数情况下,你应该像下面那样在xml
中通过设置视图背景来应用这个功能:
?android:attr/selectableItemBackground
用于有界涟漪效果。?android:attr/selectableItemBackgroundBorderless
用于拓展到视图外面的涟漪效果。这个效果将被绘制并局限于此视图具有非空背景的最近的你控件中。注意:selectableItemBackgroundBorderless
是API 21中的新属性。
另外,你也可以通过使用ripple
元素的xml
资源来定义RippleDrawable
。
你可能给RippleDrawable
对象布置颜色。要想改变默认的触摸反馈颜色,得使用该主题的android:colorControlHighlight
属性。
使用揭露效果
在你想要显示或者隐藏一组UI元素时,揭露动画向用户提供了持续地可见性。ViewAnimationUtils.createCircularReveal()
方法使你在揭露或隐藏视图时产生一个裁剪圈似的动画。
使用如下效果来揭露之前不可见的视图:
1 // previously invisible view 2 View myView = findViewById(R.id.my_view); 3 // get the center for the clipping circle 4 int cx = (myView.getLeft() + myView.getRight()) / 2; 5 int cy = (myView.getTop() + myView.getBottom()) / 2; 6 // get the final radius for the clipping circle 7 int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); 8 // create the animator for this view (the start radius is zero) 9 Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); 10 // make the view visible and start the animation 11 myView.setVisibility(View.VISIBLE); 12 anim.start();
使用如下效果来隐藏之前可见的视图:
1 // previously visible view 2 final View myView = findViewById(R.id.my_view); 3 // get the center for the clipping circle 4 int cx = (myView.getLeft() + myView.getRight()) / 2; 5 int cy = (myView.getTop() + myView.getBottom()) / 2; 6 // get the initial radius for the clipping circle 7 int initialRadius = myView.getWidth(); 8 // create the animation (the final radius is zero) 9 Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0); 10 // make the view invisible when the animation is done 11 anim.addListener(new AnimatorListenerAdapter() { 12 @Override 13 public void onAnimationEnd(Animator animation) { 14 super.onAnimationEnd(animation); 15 myView.setVisibility(View.INVISIBLE); 16 } 17 }); 18 // start the animation 19 anim.start();
自定义Activity
过渡效果
符合材料设计的应用中的Activity
过渡效果,在不同状态之间,通过常用元素之间的动作和转换,提供了视觉连接。你可以为Activity
之间出入过渡和共享元素过渡效果指定自定义动画。
进入过渡效果决定了activity
中的视图组是如何进入屏幕的。例如,在explode
进入过渡效果中,视图从外面进入屏幕,并飞入屏幕中心。
退出过渡效果决定了activity
中的视图组是如何退出屏幕的。例如,在explode
退出过渡效果中,视图是从中心位置退出屏幕的。
共享元素过渡效果决定了两个activity
之间共享的视图在这些activity
之间是如何过渡的。例如,如果两个activity
拥有不同的位置和尺寸的相同的图片,共享元素的changeImageTransform
过渡效果将在这些activity
之间顺滑地平移和缩放这些图片。
Android 5.0(API 21)
支持这些出入过渡效果:
explode
—从屏幕中心位置移入移出视图;slide
—从屏幕地边缘位置移入移出视图;fade
—通过改变视图的透明度从屏幕中添加或删除视图;任何继承了Visibility
类的过渡效果都可以作为出入过渡效果。
Android 5.0(API 21)
支持这些共享元素过渡效果:
changeBounds
—使目标视图的布局边缘变化生成动画效果;changeClipBounds
—使目标视图的剪裁边缘变化生成动画效果;changeTransform
—使目标视图的缩放和旋转变化生成动画效果;changeImageTransform
—使目标视图的尺寸和缩放变化生成动画效果;当你在应用中使用activity
过渡效果时,在Activity
的进入和退出之间默认的交错退色效果被激活。
指定自定义过渡效果
首先,在你定义一个继承自材料主题的风格时,通过android:windowContentTransitions
属性激活窗口内容过渡效果。你也可以在风格定义中指定出入和共享元素过渡效果:
1 <style name="BaseAppTheme" parent="android:Theme.Material"> 2 <!-- enable window content transitions --> 3 <item name="android:windowContentTransitions">true</item> 4 5 <!-- specify enter and exit transitions --> 6 <item name="android:windowEnterTransition">@transition/explode</item> 7 <item name="android:windowExitTransition">@transition/explode</item> 8 9 <!-- specify shared element transitions --> 10 <item name="android:windowSharedElementEnterTransition"> 11 @transition/change_image_transform</item> 12 <item name="android:windowSharedElementExitTransition"> 13 @transition/change_image_transform</item> 14 </style>
这个例子子中的change_image_transform
过渡效果定义如下:
1 <!-- res/transition/change_image_transform.xml --> 2 <!-- (see also Shared Transitions below) --> 3 <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> 4 <changeImageTransform/> 5 </transitionSet>
changeImageTransform
元素对应于ChangeImageTransform
类。
要想激活代码中的窗口内容过渡效果,得调用Window.requestFeature()
方法:
1 // inside your activity (if you did not enable transitions in your theme) 2 getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); 3 // set an exit transition 4 getWindow().setExitTransition(new Explode());
要在代码中指定过渡效果,调用这些方法使用Transition
类:
方法setEnterTransition()
和setSharedElementExitTransition()
给调用者Acivity
定义了退出过渡效果,而方法setEnterTransition()
和setSharedElementEnterTransition()
为被调用者定义了进入过渡效果。
为了获取过渡的全部效果,你必须激活调用和被调用Activity
的窗口内容过渡效果。否则的话,否则的话,调用者Activity
将会启动退出过渡效果,但是你会看到这个窗口过渡效果的(例如缩放或者褪色)。
为了尽可能早的启动进入过渡效果,得在被调用Activity
中使用Window.setAllowEnterTransitionOverlap()
。这将使你拥有更多戏剧般美妙的进入过渡效果。
启动使用过渡效果的Activity
如果你对Activity
启动并设置了退出过渡效果,过渡效果将如下所示一样,在你启动另外一个Activity
时被激活:startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
如果你对第二个Activity
设置了进入过渡效果,这个过渡效果将会在该Activity
启动时被激活。要想在启动另外一个Activity
时取消过渡效果,你需要提供null
的候选Bundle
。
启动拥有共享元素的Activity
为了在拥有共享元素的两个Activity
之间的过渡产生动画效果:
1 // get the element that receives the click event 2 final View imgContainerView = findViewById(R.id.img_container); 3 // get the common element for the transition in this activity 4 final View androidRobotView = findViewById(R.id.image_small); 5 // define a click listener 6 imgContainerView.setOnClickListener(new View.OnClickListener() { 7 @Override 8 public void onClick(View view) { 9 Intent intent = new Intent(this, Activity2.class); 10 // create the transition animation - the images in the layouts 11 // of both activities are defined with android:transitionName="robot" 12 ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, androidRobotView, "robot"); 13 // start the new activity 14 startActivity(intent, options.toBundle()); 15 } 16 });
对于代码中生成的动态共享视图而言,要在两个Activity
中使用View.setTransitionName()
方法指定共同的元素名字。
为了结束掉第二个Activity
时逆转屏幕过渡效果动画,要调用Activity.finishAfterTransition()
方法而非Activity.finish()
。
启动拥有多个共享元素的Activity
要使拥有多于一个共享元素的两个Activity
的屏幕过渡产生动画效果,要在拥有android:transitionName
属性(或者在两个Activity
中使用View.setTransitionName()
方法)的两个布局文件中定义共享元素,并且要按照如下所示创建ActivityOptions
对象:
1 ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, Pair.create(view1, "agreedName1"), Pair.create(view2, "agreedName2"));
使用弧形运动
材料设计中的动画依赖于实现了时间加速和空间运动的弧形。Android 5.0(API 21)
以上,你可以给动画自定义计时弧形和弧形运动模式。
PathInterpolator
类是新的基于贝赛尔曲线或者Path
类的加速器。这个加速器详细说明了在1x1
方格中的动作曲线,它的锚头指在(0, 0)
和(1, 1)
之间,并且控制点使用了构造函数中声明的值。你也可以在xml
文件中定义路径加速器:
1 <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" 2 android:controlX1="0.4" 3 android:controlY1="0" 4 android:controlX2="1" 5 android:controlY2="1"/>
系统为材料设计中的三个基础弧线提供了xml
资源:
1 @interpolator/fast_out_linear_in.xml 2 @interpolator/fast_out_slow_in.xml 3 @interpolator/linear_out_slow_in.xml
你可以把PathInterpolator
对象传给Animator.setInterpolator()
方法。
ObjectAnimator
对象拥有新的构造器,使得你能够坐标沿着一个一次使用两个或者多个属性的路径。例如,下面的动画使用了Path
对象使得视图的X
和Y
属性产生动画效果:
1 ObjectAnimator mAnimator; 2 mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); 3 ... 4 mAnimator.start();
将视图的状态变化产生动画效果
StateListAnimator
对象让你定义在视图状态变化时运行的动画。下面的例子向你展示如何将StateListAnimator
定义成xml
资源:
1 <!-- animate the translationZ property of a view when pressed --> 2 <selector xmlns:android="http://schemas.android.com/apk/res/android"> 3 <item android:state_pressed="true"> 4 <set> 5 <objectAnimator android:propertyName="translationZ" 6 android:duration="@android:integer/config_shortAnimTime" 7 android:valueTo="2dp" 8 android:valueType="floatType"/> 9 <!-- you could have other objectAnimator elements 10 here for "x" and "y", or other properties --> 11 </set> 12 </item> 13 <item android:state_enabled="true" 14 android:state_pressed="false" 15 android:state_focused="true"> 16 <set> 17 <objectAnimator android:propertyName="translationZ" 18 android:duration="100" 19 android:valueTo="0" 20 android:valueType="floatType"/> 21 </set> 22 </item> 23 </selector>
要将自定义的视图状态动画添加到视图上,要像上述例子一样,将一个动画使用xml
资源文件中的selector
元素定义出来,而且把它通过android:stateListAnimator
属性分配到你的视图上。要在代码中把状态列表动画分配到视图中,要使用AnimationInflater.loadStateListAnimator()
方法,并且使用View.setStateListAnimator()
方法把动画分配到你的视图中。
当你的主题继承自材料主题时,按钮在默认情况下有Z
动画。要在你的按钮中避免这种行为,需要把android:stateListAnimator
属性设置成@null
。
AnimatorStateListDrawable
类让你创建相关联状态变化时展示动画的drawable
。Android 5.0
中的某些系统控件默认使用这些动画。下面的例子展示了如何使用xml
资源定义AnimatedStateListDrawable
类:
1 <!-- res/drawable/myanimstatedrawable.xml --> 2 <animated-selector 3 xmlns:android="http://schemas.android.com/apk/res/android"> 4 5 <!-- provide a different drawable for each state--> 6 <item android:id="@+id/pressed" android:drawable="@drawable/drawableP" 7 android:state_pressed="true"/> 8 <item android:id="@+id/focused" android:drawable="@drawable/drawableF" 9 android:state_focused="true"/> 10 <item android:id="@id/default" 11 android:drawable="@drawable/drawableD"/> 12 13 <!-- specify a transition --> 14 <transition android:fromId="@+id/default" android:toId="@+id/pressed"> 15 <animation-list> 16 <item android:duration="15" android:drawable="@drawable/dt1"/> 17 <item android:duration="15" android:drawable="@drawable/dt2"/> 18 ... 19 </animation-list> 20 </transition> 21 ... 22 </animated-selector>
使矢量Drawable
产生动画
矢量图可缩放但却不损失精度。AnimatedVectorDrawable
类让你将矢量图的属性产生动画。
你通常情况下在下面三个xml
文件中定义动画矢量图:
可动画矢量图能够将和
等元素的属性产生动画。元素定义了一系列的
path
和group
,而
元素定义了要被绘制的path
。
当你定义想要产生动画的矢量图时,要使用android:name
属性对group
和path
分配唯一的名字。由此,你可以用从你的动画定义中引用它们,例如:
1 !-- res/drawable/vectordrawable.xml --> 2 <vector xmlns:android="http://schemas.android.com/apk/res/android" 3 android:height="64dp" 4 android:width="64dp" 5 android:viewportHeight="600" 6 android:viewportWidth="600"> 7 <group 8 android:name="rotationGroup" 9 android:pivotX="300.0" 10 android:pivotY="300.0" 11 android:rotation="45.0" > 12 <path 13 android:name="v" 14 android:fillColor="#000000" 15 android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> 16 </group> 17 </vector>
可动画矢量图定义通过他们的名字引用了group
和path
:
1 <!-- res/drawable/animvectordrawable.xml --> 2 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" 3 android:drawable="@drawable/vectordrawable" > 4 <target 5 android:name="rotationGroup" 6 android:animation="@anim/rotation" /> 7 <target 8 android:name="v" 9 android:animation="@anim/path_morph" /> 10 </animated-vector>
这些动画定义表示ObjectAnimator
或AnimatorSet
对象。这个例子中的第一个动画器将目标group
旋转了360度:
1 <!-- res/anim/rotation.xml --> 2 <objectAnimator 3 android:duration="6000" 4 android:propertyName="rotation" 5 android:valueFrom="0" 6 android:valueTo="360" />
例子中的第二个动画器使矢量图的路径从一种形状变化为另外一种。两个路径必须兼容于产生形变:它们必须拥有相同数量的命令,每个命令必须有相同数量的参数:
1 <!-- res/anim/path_morph.xml --> 2 <set xmlns:android="http://schemas.android.com/apk/res/android"> 3 <objectAnimator 4 android:duration="3000" 5 android:propertyName="pathData" 6 android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" 7 android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" 8 android:valueType="pathType" /> 9 </set>