Android属性动画(Animator)的优势

我们现在有一个简单需求:我们的界面中有一个Button和一个ImageView ,我们点击ImageView产生点击事件,然后我们点击Button来移动这个ImageView,让这个ImageView沿着X轴移动500,并且在移动之后我们再次点击ImageView的点击事件让它响应我们的ImageView的点击事件!


请记住我们的第一个需求!我们开始分析:


Android起初有两种动画:Frame Animation(逐帧动画) Tween Animation(补间动画),但是在用的时候发现这两种动画有时候并不能满足我们的一些需要,所以Google在Androi3.0的时候推出了(Property Animation)属性动画,至于为什么前边的两种动画不能满足我们的需要,请往下看:

Frame Animation(逐帧动画)



  逐帧动画就是UI设计多张图片组成一个动画,然后将它们组合链接起来进行动画播放。


该方式类似于早期电影的制作原理:具体实现方式就不多说了,你只需要让你们的UI出多张图片,然后你顺序的组合就可以(前提是UI给您做图)


Tween Animation(补间动画) 

  


  Tween Animation:是对某个View进行一系列的动画的操作,包括淡入淡出(Alpha),缩放(Scale),平移(Translate),旋转(Rotate)四种模式

   咱们用一个列子来说明这种方式:

   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>

 注:这个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坐标产生动画,这样补间动画就不能满足了。


2Tween 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,alphascaleXscaleY)

                    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();




转载于:https://my.oschina.net/u/934459/blog/509671

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值