咱们如今有一个简单需求:咱们的界面中有一个Button和一个ImageView ,咱们点击ImageView产生点击事件,而后咱们点击Button来移动这个ImageView,让这个ImageView沿着X轴移动500,而且在移动以后咱们再次点击ImageView的点击事件让它响应咱们的ImageView的点击事件!html
请记住咱们的第一个需求!咱们开始分析:java
Android起初有两种动画:Frame Animation(逐帧动画) Tween Animation(补间动画),可是在用的时候发现这两种动画有时候并不能知足咱们的一些须要,因此Google在Androi3.0的时候推出了(Property Animation)属性动画,至于为何前边的两种动画不能知足咱们的须要,请往下看:android
Frame Animation(逐帧动画)app
逐帧动画就是UI设计多张图片组成一个动画,而后将它们组合连接起来进行动画播放。异步
该方式相似于早期电影的制做原理:具体实现方式就很少说了,你只须要让大家的UI出多张图片,而后你顺序的组合就能够(前提是UI给您作图)
ide
Tween Animation(补间动画) 性能
Tween Animation:是对某个View进行一系列的动画的操做,包括淡入淡出(Alpha),缩放(Scale),平移(Translate),旋转(Rotate)四种模式优化
我们用一个列子来讲明这种方式:动画
eg:首先咱们重建一个项目,而后写一个xmllua
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="click" android:background="@drawable/ic_launcher" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:onClick="move" android:text="Move" /> </RelativeLayout>
注:这个XML咱们后边还会一直用到
接着咱们须要在咱们的Activity中加入代码
package com.example.animator1; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.view.animation.TranslateAnimation; import android.widget.Toast; public class Animator1Activity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animator1); } public void click(View view){ Toast.makeText(getApplicationContext(), "clicked", Toast.LENGTH_SHORT).show(); } @SuppressLint("NewApi") public void move(View view){ TranslateAnimation animation = new TranslateAnimation(0, 500, 0, 0); animation.setDuration(1000); animation.setFillAfter(true); //当动画中止后就会停留在动画结束的位置 ImageView imageView = (ImageView) findViewById(R.id.image); imageView.startAnimation(animation); } }
而后咱们运行咱们的代码会发现,咱们的动画运行都没问题,可是出现了一个问题,那就是咱们的click事件,在动画位置移动以前咱们点击ImageView是会打印出“clicked”,可是当咱们在动画位置移动以后再次点击ImageView,发现“clicked”不打印了,可是咱们点击原先ImageView动画移动以前的位置会发现点击事件又是能够,从这咱们就能够得出一个结论:传统的Animation动画并不适用于作进行动画交互的效果,并且Animation动画的效果是重复调用咱们的Ondraw方法进行重绘,这样会存在内存,性能的一些问题。
咱们能够得出Tween Animation(补间动画)的一些缺点:
1:Tween Animation(补间动画)只是针对于View,超脱了View就没法操做了,这句话的意思是:假如咱们须要对一个Button,ImageView,LinearLayout或者是其余的继承自View的各类组件进行动画的操做时,Tween Animation是能够帮咱们完成咱们须要完成的功能的,可是若是咱们须要用到对一个非View的对象进行动画操做的话,那么补间动画就没办法实现了。举个例子:好比咱们有一个自定义的View,在这个View中有一个Point对象用于管理坐标,而后在onDraw()方法中的坐标就是根据该Pointde坐标值进行绘制的。也就是说,若是咱们能够对Point对象进行动画操做,那么整个自定义的View,那么整个自继承View的当前类就都有了动画,可是咱们的目的是不想让View有动画,只是对动画中的Point坐标产生动画,这样补间动画就不能知足了。
2:Tween Animation动画有四种动画操做(移动,缩放,旋转,淡入淡出),可是咱们如今有个需求就是将当前View的背景色进行改变呢?抱歉Tween Animation是不能帮助咱们实现的。
3:Tween Animation动画只是改变View的显示效果而已,可是不会真正的去改变View的属性,举个例子:咱们如今屏幕的顶部有一个小球,而后经过补间动画让他移动到右下角,而后咱们给这个小球添加了点击事件,但愿位置移动到右下角的时候点击小球能的放大小球。可是点击事件是绝对不会触发的,缘由是补间动画只是将该小球绘制到了屏幕的右下角,实际这个小球仍是停在屏幕的顶部,因此你在右下角点击是没有任何反应的。
因此根据这些问题Google在Android3.0以后推出了一种全新的动画模式Property Animation(属性动画)。
Property Animatior(属性动画)
属性动画是Android3.0以后引进的,它更改的是动画的实际属性,在Tween Animation(补间动画)中,其改变的是View的绘制效果,真正的View的属性是改变不了的,好比你将你的Button位置移动以后你再次点击Button是没有任何点击效果的,或者是你如何缩放你的Button大小,缩放后的有效的点击区域仍是只有你当初初始的Button的大小的点击区域,其位置和大小的属性并无改变。而在Property Animator(属性动画)中,改变的是动画的实际属性,如Button的缩放,Button的位置和大小属性值都会发生改变。并且Property Animation不止能够应用于View,还能够应用于任何对象,Property Animation只是表示一个值在一段时间内的改变,当值改变时要作什么事情彻底是你本身决定的。
在Property Animation中,能够对动画应用一下的属性:
Duration:动画的持续时间
TimeInterPolation:属性值的计算方式,如先快后慢
TypeEvaluator:根据属性的开始,结束值与TimeInterpolation计算出的因子计算出当前时间的属性值
Repeat Count and behavoir:重复次数与方式,如播放3次,5次,无限循环,可让此动画一直重复,或者是播放完时再反向播放。
Animation sets:动画集合,便可以同时对一个对象应用几个动画,这些动画能够同时播放也能够对不一样的动画设置不一样开始偏移。
Frame refresh delay:多少时间刷新一次,即每隔多长时间计算一次属性值,默认为10s,最终刷新时间还受系统进程的调度与硬件的影响。
属性动画有几种模式:ObjectAnimator ViewAnimator AnimationSet TypeEvalutors TimeInterplator
ObjectAnimator:
真真实实的改变了动画的属性。咱们如今用ObjectAnimator的几种实现方式实现刚才咱们用Tween Animation的实现点击按钮图片移动而且点击图片响应事件
eg:首先咱们须要用到上边咱们定义的xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="click" android:background="@drawable/ic_launcher" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:onClick="move" android:text="Move" /> </RelativeLayout>
咱们用第一种方式实现:
1:主要看代码:
package com.example.animator1; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.view.animation.TranslateAnimation; import android.widget.Toast; public class Animator1Activity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animator1); } public void click(View view){ Toast.makeText(getApplicationContext(), "clicked", Toast.LENGTH_SHORT).show(); } @SuppressLint("NewApi") public void move(View view){ //使用ObjectAnimator实现上述实现方式 //translationY :x轴移动, X:最终到达的位置 ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 500f); animator.setDuration(1000); animator.start(); } }
咱们先来看看 "ObjectAnimator.ofFloat"源码:
/** * Constructs and returns an ObjectAnimator that animates between float values. A single * value implies that that value is the one being animated to. Two values imply starting * and ending values. More than two values imply a starting value, values to animate through * along the way, and an ending value (these values will be distributed evenly across * the duration of the animation). * * @param target The object whose property is to be animated. This object should * have a public method on it called <code>setName()</code>, where <code>name</code> is * the value of the <code>propertyName</code> parameter. * @param propertyName The name of the property being animated. * @param values A set of values that the animation will animate between over time. * @return An ObjectAnimator object that is set up to animate between the given values. */ public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setFloatValues(values); return anim; }
从源码中大体咱们能够看出:target就是咱们要标识的Tag,propertyName:被设置动画的属性名称, values:动画移动的时间范围
好,代码咱们贴出来了,而后咱们来看看大体意思:
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 500f);
咱们首先实例化了一个ObjectAnimator,而后咱们来看看参数
imageView:须要更改的View
translationX:沿着X周移动(注:此处有不少属性,常见的有translationX,translationY,rotation,alpha,scaleX,scaleY)
0f, 500f :从X轴的0点位置移动到500
animator.setDuration(1000);
设置动画移动过程的时间
animator.start();
开始咱们的动画
好,咱们如今运行代码发现这正是咱们须要的效果,而且在ImageView移动以后咱们再次点击ImageView发现点击事件仍是能够被执行的,从这儿就证实了咱们先前所说。
咱们用第二种方式实现:(注:XML仍是用咱们原先定义好的XML)
1:主要看代码:
package com.example.animator1; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.view.animation.TranslateAnimation; import android.widget.Toast; public class Animator1Activity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animator1); } public void click(View view){ Toast.makeText(getApplicationContext(), "clicked", Toast.LENGTH_SHORT).show(); } @SuppressLint("NewApi") public void move(View view){ //使用ObjectAnimator实现上述实现方式 //translationY :x轴移动, X:最终到达的位置 ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 500f); animator.setDuration(1000); animator.start(); } }
咱们看看多属性动画的执行:
1:咱们经过ObjectAnimator中的各类属性进行动画异步执行 旋转-->X轴移动-->Y轴移动 eg:
// /** // * 多属性同时改变 //咱们写了三个动画。咱们发现下边这三句话是同时执行的,他是异步执行的,异步同时执行的 // */ ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f).setDuration(1000).start(); ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f).setDuration(1000).start(); ObjectAnimator.ofFloat(imageView, "translationY", 0f, 200f).setDuration(1000).start();
2:咱们发如今Android中给咱们封装了一个ProperyValueHolder,这种写法的好处是:ProperyValueHolder对界面进行了一系列的优化,这样的优化让咱们在使用的多个属性动画优化中更加方便和更加节省时间。 eg:
/** * PropertyValuesHolder:咱们发现用这种方式和上边用三个start实现的方式同样,那这样写有什么好处呢,回答是:PropertyValuesHolder对动画进行了一系列的优化,这样的一些优化使得咱们在使用多个属性动画的时候 * 更加方便更加节省之间, */ PropertyValuesHolder pl1 = PropertyValuesHolder.ofFloat( "rotation", 0f, 360f); PropertyValuesHolder pl2 = PropertyValuesHolder.ofFloat( "translationX", 0f, 200f); PropertyValuesHolder pl3 = PropertyValuesHolder.ofFloat( "translationY", 0f, 200f); ObjectAnimator.ofPropertyValuesHolder(imageView, pl1, pl2, pl3).setDuration(1000).start();
3:咱们仍是沿用第一种的方式经过onFloat中的各类属性实例化,而后咱们经过AnimatorSet来执行动画。 eg:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f); ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 360f); ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView, "translationY", 0f, 360f); AnimatorSet set = new AnimatorSet(); /** * 1 //动画异步同时执行 */ // set.playTogether(animator1, animator2, animator3); // set.setDuration(1000); // set.start(); /** * 2 //按照顺序进行动画的播放 */ // set.playSequentially(animator1, animator2, animator3); // set.setDuration(1000); // set.start(); /** * 3 //先从X轴和Y轴上同时移动 , 再在animator动画中旋转 */ set.play(animator2).with(animator3); set.play(animator1).after(animator2); set.setDuration(1000); set.start();