初识android动画(4)之属性动画

     属性动画算是Android动画里面比较麻烦的一种动画了。不过就是因为它麻烦所以也能更好地满足我们的需求。属性动画是在3.0以后添加的。功能十分强大。接下来我们将重点的讲讲。如果对其他几种动画不了解的话可以先看看我的前几篇博客初识android动画。下面的内容均在前几篇的基础上讲的。我们看一下官方提供的使用属性动画制作的酷炫的例子吧!!!

     先给出官方的API       点击打开链接

 

     属性动画与传统动画的区别

  

         当我们点击按钮的时候,一个圆由位置一转到位置二。我们也为这个圆设置一个点击事件,当点击圆的时候弹出一个Toast。我们传统的做法是什么呢?肯定是设置一个传统的TranslateAnimation属性,为其设置位置就可以了。现在我们在位置一点击圆肯定能弹出一个Toast。但是我们的位置发生变化之后,我们再去点击圆发现没有Toast了。但是我们在原来的位置一上点击发现能够Toast,怎么回事呢?这就是传统动画的弊端了。 传统动画考虑的是一个View的重新绘制。当我们执行动画的时候其实就是一个个View不断地去重新绘制。而我们的属性动画就可以很好的解决这一问题。

        属性动画一:ObjectAnimator

  ObjectAnimator是属性动画里面比较简单但是也是会经常用到的一个对象。他其实执行的是一个异步任务。我们再给出官方的API  点击打开链接

 那么我们如何去使用呢?接着前面提到的一个例子       

    我们定义了一个按钮,一张图片。点击按钮启动动画;

public class MainActivity extends Activity {
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    //图片的点击事件
    public void click(View view){
    	Toast.makeText(MainActivity.this, "点击了图片", Toast.LENGTH_SHORT).show();
    }
    
    //按钮的监听事件
    public void move(View view){
    	ImageView imageView=(ImageView) findViewById(R.id.imageView1);
    	
    	ObjectAnimator animator=new ObjectAnimator();
    	animator.ofFloat(imageView, "translationX", 0f,200f).start();
    }
 
}

 我们看到,我们用属性动画特别的简单,就是一句话,而且用属性动画,我们也很好的解决了上面的问题。当我们使用其他属性的时候,直接调用其他的就好。在这里我们使用了TranslationX.当然我们还有其他的一些属性。
       

如果我们使用ObjiecAnimation为ImageView同时定义多个动画会怎么样呢?答案就是同时会播放这几个动画。下面看一下还有没有其他的几种方法

           (1)同时使用ObjiecAnimator
   我们将上面MainActivity中的代码修改一下
ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000).start();
    	ObjectAnimator.ofFloat(imageView, "translationY", 0f,200f).setDuration(3000).start();
    	ObjectAnimator.ofFloat(imageView, "rotation", 0f,360f).setDuration(3000).start();
            (2)同时使用 PropertyVlaueHolder:
使用这种属性的好处就是他的性能好, 节省系统资源
PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("translationX",0f,200f);
    	PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("translationY", 0f,200f);
    	PropertyValuesHolder p3=PropertyValuesHolder.ofFloat("rotation", 0f,360f);
    	ObjectAnimator.ofPropertyValuesHolder(imageView, p1,p2,p3).setDuration(3000).start();
            (3)使用AnimatorSet
    	ObjectAnimator animator1=ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000);
    	ObjectAnimator animator2=ObjectAnimator.ofFloat(imageView, "translationY", 0f,200f).setDuration(3000);
    	ObjectAnimator animator3=ObjectAnimator.ofFloat(imageView, "rotation", 0f,360f).setDuration(3000);
    	AnimatorSet set=new AnimatorSet();
    	set.playTogether(animator1,animator2,animator3);
    	set.start();
 我们使用以上的三种方法都可以实现同时播放我们的好几种动画。其中AnimatorSet功能最为强大。不仅仅可以同时播放好几种动画,还可以控制动画的播放顺序
          //按照顺序依次播放
    	  set.playSequentially(animator1,animator2,animator3);
    	 //动画2和动画3同时播放,动画一在他们之后播放
    	  set.play(animator2).with(animator3);
    	  set.play(animator1).after(animator2);

    属性动画二:监听事件

     有时候我们在动画播放的过程中,或者前后会引发一系列事件,这时候我们就可以添加
ObjectAnimator animator1=ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000);
    	//添加监听事件
    	animator1.addListener(new AnimatorListener() {
			
			@Override
			public void onAnimationStart(Animator animation) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onAnimationRepeat(Animator animation) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onAnimationEnd(Animator animation) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onAnimationCancel(Animator animation) {
				// TODO Auto-generated method stub
				
			}
		});
    	
    	
    	//有选择的添加监听事件
    	animator1.addListener(new AnimatorListenerAdapter() {
    		@Override
    		public void onAnimationEnd(Animator animation) {
    			// TODO Auto-generated method stub
    			super.onAnimationEnd(animation);
    		}
		});
代码很简单一眼就能明白。

       属性动画三:  ValueAnimator数值发生器

  什么是ValueAnimator呢?
       前面我们提到ObjectAnimator可以定义一个动画到View的某一个属性。其实ObjectAnimator就是继承了ValueAnimator。 而ValueAnimator则不会产生这样一种效果。它的本质就是一个数值发生器。他可以产生你想要的各种数值。他可以计算属性动画中每一步的具体动画效果。 ValueAnimator会根据动画已进行的时间与其持续的总时间的比值产生一个0~1的时间因子,有了这样一个时间因子,经过相应的变换,就可以根据startValue()和endValue()来生产中间的相应值。同时,通过插值器的使用,可以进一步地控制每一个时间因子产生值的变化速率。下面看一看该如何用?这里使用一个数值计算器。
        我们要实现的效果是什么呢,就是在点击一个按钮之后,按钮的显示内容会从0-10不断地递增。如果按照以前的做法,我们肯定是在线程中定义一个for循环,每一段时间更新一个数值。其实呀,这种方法是非常的耗费系统资源的。ValueAnimator也可以实现这样的一种效果。
      
  下面是实现的代码
  
public class MyActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		setContentView(R.layout.my_activity);
		super.onCreate(savedInstanceState);
	}
	
	public void click(View view){
		//获得Button对象
		final Button button=(Button)findViewById(R.id.my_button);
		//新建一个ValueAnimator,让其中的数值从0-10
		ValueAnimator animator=ValueAnimator.ofInt(0,10);
		//从0-10在10秒内变化
		animator.setDuration(10000);
		//为其添加事件
		animator.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				//获得ValueAnimator的植
				Integer value=(Integer) animation.getAnimatedValue();
				button.setText(""+value);
			}
		});
		animator.start();//启动动画
	}
	
}
         我们看到没有使用线程。也可以实现。现在大家应该能够自然而言的想到一些其他的一些应用场景了吧。例如在0-3之间我们产生一个时间,3-7之间做另外一件事等等。上面我们直接使用的ofInt。这是谷歌给我定义好的一种模式。那我们能不能自己定义一些数值计算器呢?答案是肯定的。
//自定义数值计算器
		ValueAnimator animator=ValueAnimator.ofObject(new TypeEvaluator<PointF>() {
			
			//通过evaluate返回各种各样的植,我们拿到这些值之后就可以为所欲为了。

			@Override
			public PointF evaluate(float arg0, PointF arg1, PointF arg2) {
				// TODO Auto-generated method stub
				return null;
			}
		});
 fraction:   :时间因子,从0-1之间变化              arg1   :开始值            arg2  :结束值
我们自定义这些值可以应用到插值器中:定义自己的插值器。如果对插值其不了解的话。看我的另外一篇博客
   下面给一张插值器的数值变化表,
    

    总结:

            下面总结了一下属性动画中常用的一些方法类和接口。
                 
    接下来根据前面学的知识,做一个小的案例。先看一下效果:
      
先在我们res/drawable/文件中添加一些列图片。然后在布局文件中声明:
<FrameLayout 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/imageView_h"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/h" />
    
   <ImageView
        android:id="@+id/imageView_g"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/g" />
   
   <ImageView
        android:id="@+id/imageView_f"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/f" />
    
   <ImageView
        android:id="@+id/imageView_e"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/e" />
    
    <ImageView
        android:id="@+id/imageView_d"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/d" />
    
     <ImageView
        android:id="@+id/imageView_c"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/c" />
    
     <ImageView
        android:id="@+id/imageView_b"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/b" />
    
     <ImageView
        android:id="@+id/imageView_a"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/a" />
  
</FrameLayout>
然后在我们activity中运用就可以了。
public class MainActivity1 extends Activity implements OnClickListener {

	//定义一些图片资源
	private int[] res = { R.id.imageView_a, R.id.imageView_b, R.id.imageView_c,
			R.id.imageView_d, R.id.imageView_e, R.id.imageView_f, R.id.imageView_g, R.id.imageView_h };

	//保存图片
	private List<ImageView> imageViewList = new ArrayList<ImageView>();

	//用于控制图片伸缩开关
	private boolean flag=true;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		//将图片添加进来
		for (int i = 0; i < res.length; i++) {
			ImageView imageView = (ImageView) findViewById(res[i]);
			imageView.setOnClickListener(this);
			imageViewList.add(imageView);
		}
	
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.imageView_a:	
			if(flag){
				startAnim();
			}else{
				stopAnim();
			}
			break;
		}
	}
	
	//停止播放动画
	@SuppressLint("NewApi")
	private void stopAnim() {
		for (int i = 0; i < res.length; i++) {
			ObjectAnimator animator = ObjectAnimator.ofFloat(
					imageViewList.get(i), "translationY", i * 100, 0f);
			animator.setInterpolator(new BounceInterpolator());		//插值器	
			animator.setDuration(1000);
			animator.setStartDelay(i * 500);
			animator.start();
			flag=true;
		}

	}

	//开始播放动画
	@SuppressLint("NewApi")
	private void startAnim() {
		for (int i = 1; i < res.length; i++) {
			ObjectAnimator animator = ObjectAnimator.ofFloat(
					imageViewList.get(i), "translationY", 0f, i * 100);
			AnimatorSet mset=new AnimatorSet();
			mset.playTogether(animator);
			mset.setDuration(1000);
			mset.setStartDelay(i*500);
			mset.setInterpolator(new BounceInterpolator());		//插值器	
			mset.start();
			flag=false;
		}

	}

}
    如果看懂了源码之后你也可以自己修改制作各种不同的效果。
点击下载源码:点击下载


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值