Android中PropertyAnimation属性动画详解(一)

在之前的文章中已经讲了帧动画frame-by-frame animation和补间动画tweened
animation,其实这两种动画原理好简单,都是按照预先固定的动画模式来播放的,帧动画将一张张单独的图片,然后把它们连贯起来进行播放,就形成了动画效果,补间动画则是可以对View对象进行一系列的动画操作,包括淡入淡出、缩放、平移、旋转四种,不过这几种都是完全按照我们预先设置好的效果来执行,不能动态的改变,所以,在Android3.0以后就引入了属性动画PropertyAnimation来满足一些特定的需求,基本来说,属性动画的功能远远比前两种动画功能强大,因为它既可以对View对象操作,也可以对非View对象操作,所以说它的功能是非常强大的,好了,现在来详细介绍一下属性动画吧。

新引入的属性动画机制已经不再是针对于View来设计的了,也不限定于只能实现移动、缩放、旋转和淡入淡出这几种动画操作,同时也不再只是一种视觉上的动画效果了。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。所以我们仍然可以将一个View进行移动或者缩放,但同时也可以对自定义View中的Point对象进行动画操作了。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,就ok了。

既然属性动画的实现机制是通过对目标对象进行赋值并修改其“属性”来实现的,这个怎么理解呢?假如我们通过属性动画来移动一个按钮,那么这个按钮就是真正的移动了,而不再是仅仅在另外一个位置绘制了而已,即是控件的真实位置移动了,而补间动画则是在另外一个地方绘制了一个一模一样的而已,真实位置还是在原来的地方。

好了,下面通过代码来具体看怎么实现属性动画吧。

ValueAnimator

ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。

但是ValueAnimator的用法却一点都不复杂,我们先从最简单的功能看起吧,比如说想要将一个值从1平滑过渡到0,时长300毫秒,就可以这样写:

ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f);
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float value = (float) animation.getAnimatedValue(); //得到动画变化的属性值
        Log.d("zxy", "" + value);
    }
});
anim.start(); 

很简单吧,调用ValueAnimator的ofFloat()方法就可以构建出一个ValueAnimator的实例,ofFloat()方法当中允许传入多个float类型的参数,这里传入1和0就表示将值从1平滑过渡到0,然后调用ValueAnimator的setDuration()方法来设置动画运行的时长,最后调用start()方法启动动画。

用法就是这么简单,现在如果你运行一下上面的代码,动画就会执行了。可是这只是一个将值从0过渡到1的动画,又看不到任何界面效果,我们怎样才能知道这个动画是不是已经真正运行了呢?这就需要打印监听器里面的内容来看下效果:

从打印日志的值我们就可以看出,ValueAnimator确实已经在正常工作了,值在300毫秒的时间内从1平滑过渡到了0,而这个计算工作就是由ValueAnimator帮助我们完成的。另外ofFloat()方法当中是可以传入任意多个参数的,因此我们还可以构建出更加复杂的动画逻辑,比如说将一个值在5秒内从0过渡到5,再过渡到3,再过渡到10,就可以这样写:

ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f); 然后再开启动画即可。当然ValueAnimtor还有两个常用方法,即:ValueAnimator.ofInt(),ValueAnimator.ofObject(),除此之外,我们还可以调用setStartDelay()方法来设置动画延迟播放的时间,调用setRepeatCount()和setRepeatMode()方法来设置动画循环播放的次数以及循环播放的模式,循环模式包括RESTART和REVERSE两种,分别表示重新播放和倒序播放的意思。

ObjectAnimator

相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。

不过虽说ObjectAnimator会更加常用一些,但是它其实是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator仍然是整个属性动画当中最核心的一个类。那么既然是继承关系,说明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它们的用法也非常类似,下面直接看代码:

private void startPropertyAnimOne() {//设置透明度变化从1——>0.1——>1——>0.5——>1,意思就是该对象经历四次透明度的渐变
		ObjectAnimator anim = ObjectAnimator.ofFloat(mTvText, "alpha", 1f,
				0.1f, 1f, 0.5f, 1f);//第一个参数传入的是任意对象,第二个参数传入的是想要对该对象的哪个属性进行动画操作,第三个参数是一个可变数组,描述的是该动画的初始值和结束值,动画的渐变效果是由ValueAnimator内部算法机制实现过度效果
		anim.setDuration(5000);//持续时间
		anim.addUpdateListener(new AnimatorUpdateListener() {//添加一个动画监听器,在动画执行过程中不停的回调

			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				float value = (Float) animation.getAnimatedValue();//得到动画变化的属性值
				Log.v("zxy", value+"");//从中可以看到透明度值会从1.0缓慢的变化到0.1再到1.0再到0.5再到1.0
			}
		});
		anim.start();
	}

效果如下:

private void startPropertyAnimTwo(){//设置旋转360度
		ObjectAnimator anim = ObjectAnimator.ofFloat(mTvText, "rotation", 0f,360f);
		anim.setDuration(5000);
		anim.start();
	}

再看看旋转效果:

private void startPropertyAnimThree(){//设置往x轴方向偏移然后回到原来的位置
		float translationX = mTvText.getTranslationX();//得到该控件移动前的X轴方向上的坐标
		ObjectAnimator anim = ObjectAnimator.ofFloat(mTvText, "translationX", translationX,-500f,translationX);//向右移动500像素,然后再移动到原来的位置
		anim.setDuration(5000);
		anim.start();
	}

移动后效果如下:

private void startPropertyAnimFour(){//把TextView在垂直方向上放大3倍再还原
		ObjectAnimator anim = ObjectAnimator.ofFloat(mTvText, "scaleY", 1f, 3f, 1f);
		anim.setDuration(5000);
		anim.start();
	}

伸缩效果如下:

好了,上面就把一些基本变换动画简单的通过代码说明了一下,那么,这时候就有人有疑问了?在这段代码中:ObjectAnimator.ofFloat(mTvText, "alpha", 1f,0.1f, 1f);你怎么知道前面那个对象有alpha这个属性呢?那么第二个参数究竟可以传入什么参数呢?那么针对这个疑问,回答就是第二个参数可以是任意值,这是不是很疑惑呢?因为ObjectAnimator就是针对对象来设计的,并不是只针对View对象而设计的,所以第二个参数就是某个对象中的某个属性,然后该对象根据所赋的属性值来决定动画的表现效果。

那么textview对象中是不是有alpha属性这个值呢?没有,不仅textview没有这个属性,连它所有的父类也是没有这个属性的!这就奇怪了,textview当中并没有alpha这个属性,ObjectAnimator是如何进行操作的呢?怎么可以实现动画效果呢?其实ObjectAnimator内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法,然而TextView中并没有setAlpha和getAlpha方法啊?的却是这样,但是TextView是继承自View啊,我们通过查找View中的方法,发现了这两个方法,并且其它的rotation、translationX、等get和set方法也有,那么答案就有了,任何继承自View的类都有这些方法,通过set方法而把这个属性值设置给该对象,因此alpha属性才有所作用。

那么如果我们要使用复合动画呢?

实现复合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:

  • after(Animator anim)   将现有动画插入到该传入的动画(就是anim)之后执行
  • after(long delay)   将现有动画延迟指定毫秒后执行
  • before(Animator anim)   将现有动画插入到该传入的动画(就是anim)之前执行
  • with(Animator anim)   将现有动画和传入的动画同时执行

好的,有了这四个方法,我们就可以实现复合动画了,比如我们想要先让这个字体伸缩后再旋转的同时改变透明度,就可以这样做:

//复合动画
	private void animatorSet(){
		ObjectAnimator anim1 = ObjectAnimator.ofFloat(mTvText, "alpha", 1f,
				0.1f, 1f, 0.5f, 1f);
		ObjectAnimator anim2 = ObjectAnimator.ofFloat(mTvText, "rotation", 0f,360f);
		ObjectAnimator anim3 = ObjectAnimator.ofFloat(mTvText, "scaleY", 1f, 3f, 1f);
		AnimatorSet animSet = new AnimatorSet();//定义一个AnimatorSet对象
		animSet.play(anim1).with(anim2).after(anim3);//anim3先执行,然后再同步执行anim1、anim2。【注意】先执行的anim3动画会执行6s,然后anim1和anim2一起也执行6s
		animSet.setDuration(6000);
		animSet.addListener(new AnimatorListenerAdapter() {//设置动画监听器,监听该动画的开始、停止、取消、结束等状态,我们往往会用AnimtorListener适配器类来只实现我们需要的方法

			@Override
			public void onAnimationEnd(Animator animation) {
				super.onAnimationEnd(animation);
				//动画开始,do sthing...
			}

			@Override
			public void onAnimationStart(Animator animation) {
				super.onAnimationStart(animation);
				//动画结束,do sthing...
			}

		});
		animSet.start();
	}

效果如下:

在很多时候,我们希望可以监听到动画的各种事件,比如动画何时开始,何时结束,然后在开始或者结束的时候去执行一些逻辑处理。这个功能是完全可以实现的,Animator类当中提供了一个addListener()方法,这个方法接收一个AnimatorListener,我们只需要去实现这个AnimatorListener就可以监听动画的各种事件了。

大家已经知道,ObjectAnimator是继承自ValueAnimator的,而ValueAnimator又是继承自Animator的,因此不管是ValueAnimator还是ObjectAnimator都是可以使用addListener()这个方法的。另外AnimatorSet也是继承自Animator的,因此addListener()这个方法算是个通用的方法。

好了,属性动画的基本用法就是这些了,设置属性动画还有一个方法就是通过xml文件来设置,这就不多说了,当然还有核心用法了,那么就下次再说了!!!

时间: 2024-09-30 04:30:59

Android中PropertyAnimation属性动画详解(一)的相关文章

属性动画详解一(Property Animation)

效果图: Android动画有两类: 1.View Animation(Frame Animation,Tween Animation) 2.Property Animation 其中,上述效果是用第二类属性动画做的. 什么是属性动画? 通俗的说,属性动画就是在一定的时间内,按照一定的规律来改变对象的属性(该属性对于该对象应该是从形态(大小,位置等)上可以感受到的),从而是对象展现出动画的效果. 作用:可以定义动画来改变对象的属性( You can define an animation to

Android 属性动画 详解

认识属性动画 传统动画Animation平移方法的实现 TranslateAnimation animation = new TranslateAnimation(x轴初始位置,x轴终止位置,y轴初始位置,y轴终止位置); animation.setDuration(1000);//设置持续时间,ms单位 animation.setFillAfter(true);//设置动画结束后状态,true为保持最终状态 imageView.startAnimation(animation);//为控件添加

Android:属性动画详解

(一)简介 属性动画是Android 3.0中提供了新功能,便于对任意元素进行"平滑的过渡".众所周知,Android 之前提供的补间动画如AlphaAnimation.TranslateAnimation等都只能应用在View上,并且几乎没有任何可扩展的地方.并且,使用原来的动画无法实现颜色渐变效果,算是一个遗憾. 属性动画彻底打破了这种设计方式,不再将这些动画强制的放在View上,而是仅仅产生一系列的值,由开发人员自行使用这些值.例如,属性动画可产生1-0平滑过渡的值,把这些值应用

Android自定义view教程03---Android 属性动画 详解

1 package com.example.donghuatest; 2 3 import android.animation.ObjectAnimator; 4 import android.animation.PropertyValuesHolder; 5 import android.animation.ValueAnimator; 6 import android.animation.ValueAnimator.AnimatorUpdateListener; 7 import andro

Android中图片压缩方案详解

如感觉排版不舒服,可移步至此处查看 图片的展示可以说在我们任何一个应用中都避免不了,可是大量的图片就会出现很多的问题,比如加载大图片或者多图时的OOM问题,可以移步到Android高效加载大图.多图避免程序OOM.还有一个问题就是图片的上传下载问题,往往我们都喜欢图片既清楚又占的内存小,也就是尽可能少的耗费我们的流量,这就是我今天所要讲述的问题:图片的压缩方案的详解. 1.质量压缩法 设置bitmap options属性,降低图片的质量,像素不会减少 第一个参数为需要压缩的bitmap图片对象,

Android中CursorAdapter的使用详解

一.CursorAdapter介绍 CursorAdapter这个类是继承于BaseAdapter的它是一个虚类它为Cursor和ListView连接提供了桥梁 二.CursorAdapter详解 1.CursorAdapter的继承关系图 从图中可以看出CursorAdapter是继承于BaseAdapter的,它有一个直接的子类SimpleCursorAdapter 2.CursorAdapter的用法 我们首先看一下CursorAdapter的部分源码: /** * @see androi

android中include标签使用详解

android中include标签是为了便于控件的覆用的一个很好解决方案. 但是也有一些需要注意的地方,下面是本人在项目中碰到过的一个问题,做此记录,便于以后查看. include标签用法. 1.新建一个xml文件,命名 head.xml head.xml文件内容如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.

Android 中关于属性动画的一些思考,或许能为你解决一定的性能问题

======================================================== 作者:qiujuer 博客:blog.csdn.net/qiujuer 网站:www.qiujuer.net 开源库:Genius-Android 转载请注明出处:http://blog.csdn.net/qiujuer/article/details/42531485 --学之开源,用于开源:初学者的心态,与君共勉! ================================

Android中Activity启动模式详解,可以控制程序按home键后进来还会调用一个自己不喜欢的界面

其实这是很简单的一个问题.但是这还是要对android中activity的启动模式有相当的理解才行,当点击home键的时候,懂Android的人都知道,他会把当前activity放到后退栈中, 栈(Stack)又称堆栈,它是一种运算受限的线性表,其限制是仅允许在表的一端进行插入和删除运算.人们把此端称为栈顶,栈顶的第一个元素被称为栈顶元素,相对地,把另一端称为栈底.向一个栈插入新元素又称为进栈或入栈,它是把该元素放到栈顶元素的上面,使之成为新的栈顶元素:从一个栈删除元素又称为出栈或退栈,它是把栈