分类
Android的动画可以分为三种:
1. View动画,也叫补间动画(Tween Animation)
2. 帧动画,也叫逐帧动画(Frame Animation)
3. 属性动画
View动画
View动画的作用对象是View,分为四种:
静态创建:
创建文件夹>>右键整个module,创建resource direct,选择xml格式,名为anim
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android ="http://schemas.android.com/apk/res/android"
android:interpolator ="@[package:]anim/interpolator_resource"
android:shareInterpolator ="true"
android:duration ="3000"
android:fillAfter ="true"
>
//子类也有duration
<alpha android:fromAlpha ="0"
android:toAlpha ="0.8" />
<scale android:fromXScale ="0"
android:fromYScale ="0"
android:pivotX ="50"
android:pivotY ="50"
android:toXScale ="1"
android:toYScale ="1" />
<rotate android:fromDegrees ="0"
android:pivotX ="50"
android:pivotY ="50"
android:toDegrees ="360" />
<translate android:fromXDelta ="0"
android:fromYDelta ="0"
android:toXDelta ="100"
android:toYDelta ="100" />
</set >
android: interpolator:
插值器,默认为#android:anim/accelerate_decelerate_interpolar
android: shareInterpolator:
是否共享插值器
andorid: fillAtler:
动画结束后画面是否停留在最后一刻的位置
andorid: fillAtler:fillBefore:
动画结束后是否停留在动画的第一帧
在代码中开始动画:
public void test(View view) {
//使用AnimationUtils.loadAnimation (context,R.anim .xxx )来将静态动画加载进入代码
Animation animation = AnimationUtils.loadAnimation (this, R.anim .animation )
btn.startAnimation (animation)
}
动态创建动画
ScaleAnimation scaleAnimation = new ScaleAnimation(0f ,1f ,0f ,1f
,btn.getWidth()/2 ,btn.getHeight()/2 );
scaleAnimation.setDuration(1000 );
btn.startAnimation(scaleAnimation);
AnimationSet animationSet = new AnimationSet(false );
animationSet.addAnimation(scaleAnimation);
animationSet.setDuration(1000 );
btn.startAnimation(animationSet);
设置补间动画的监听器
private void addAnimationListener (Animation animation) {
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart (Animation animation) {
}
@Override
public void onAnimationEnd (Animation animation) {
}
@Override
public void onAnimationRepeat (Animation animation) {
}
});
}
自定义补间动画
自定义补间动画说难不难,说简单不简单,因为这主要是数学的应用;
继承Animation 这个类,
实现initialize() ,在里面做一些初始化操作
实现applyTransformation() ,在里面进行矩阵的变换,可以利用Camera来简化矩阵变化你的过程
3 D的旋转效果demo:
package com.example.android.apis.animation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.graphics.Camera;
import android.graphics.Matrix;
/**
* An animation that rotates the view on the Y axis between two specified angles.
* This animation also adds a translation on the Z axis (depth) to improve the effect.
*/
public class Rotate3dAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthZ;
private final boolean mReverse;
private Camera mCamera;
/**
* Creates a new 3D rotation on the Y axis. The rotation is defined by its
* start angle and its end angle. Both angles are in degrees. The rotation
* is performed around a center point on the 2D space, definied by a pair
* of X and Y coordinates, called centerX and centerY. When the animation
* starts, a translation on the Z axis (depth) is performed. The length
* of the translation can be specified, as well as whether the translation
* should be reversed in time.
*
* @param fromDegrees the start angle of the 3D rotation
* @param toDegrees the end angle of the 3D rotation
* @param centerX the X center of the 3D rotation
* @param centerY the Y center of the 3D rotation
* @param reverse true if the translation should be reversed, false otherwise
*/
public Rotate3dAnimation (float fromDegrees, float toDegrees,
float centerX, float centerY, float depthZ, boolean reverse) {
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
mCenterX = centerX;
mCenterY = centerY;
mDepthZ = depthZ;
mReverse = reverse;
}
@Override
public void initialize (int width, int height, int parentWidth, int parentHeight) {
super .initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
@Override
protected void applyTransformation (float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save();
if (mReverse) {
camera.translate(0.0 f, 0.0 f, mDepthZ * interpolatedTime);
} else {
camera.translate(0.0 f, 0.0 f, mDepthZ * (1.0 f - interpolatedTime));
}
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
帧动画
参考动漫,动态的画面是由多张静态的画面在单位时间内连续变换而产生的动画效果,本质上也是view动画的一种;
使用方法
在res/drawable中创建一个xml文件,以animation-list为根元素
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android ="http://schemas.android.com/apk/res/android"
android:oneshot ="false" > //是否只使用一次,false则会不停的循环
<item android:drawable ="@drawable/frame_animation_1" android:duration ="1000" />
<item android:drawable ="@drawable/frame_animatiion_2" android:duration ="1000" />
<item android:drawable ="@drawable/frame_animation_1" android:duration ="1000" />
<item android:drawable ="@drawable/frame_animatiion_2" android:duration ="1000" />
</animation-list >
public void test(View view) {
btn.setBackgroundResource (R.drawable .frame _animation)
AnimationDrawable animationDrawable = (AnimationDrawable) btn.getBackground ()
animationDrawable.start ()
}
View动画的使用场景:作为Viewgroup中子元素的出场动画
静态使用
在drawable中创建xml文件,
<layoutAnimation
xmlns:android ="http://schemas.android.com/apk/res/android"
android:animation ="@anim/animation" //指定补间动画
android:animationOrder ="normal" //子元素动画的顺序
android:delay ="10" >
</layoutAnimation >
<LinearLayout
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"
android:orientation ="vertical"
tools:context ="com.junx.viewanimationobjectanimator.Animation.AnimationActivity"
android:layoutAnimation ="@anim/layout_animation"
>
<LinearLayout
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"
android:orientation="vertical"
tools:context="com.junx.viewanimationobjectanimator.Animation.AnimationActivity"
android:layoutAnimation="@anim/layout_animation"
>
动态使用
public void layoutAnimation(ListView lv){
Animation animation = AnimationUtils.loadAnimation (this, R.anim .animation )
LayoutAnimationController layoutAnimationController
= new LayoutAnimationController(animation)
layoutAnimationController.setDelay (1 f)
layoutAnimationController.setOrder (layoutAnimationController.ORDER _RANDOM)
lv.setLayoutAnimation (layoutAnimationController)
}
View动画的使用场景:Activity的切换效果
public void test (View view) {
Intent intent = new Intent(this , FrameAnimationActivity.class);
startActivity(intent);
overridePendingTransition(android.R.anim.fade_in,android.R.anim.slide_in_left);
}
frament也可以是哟个set CustomAnimations()来设置切换效果
属性动画
View动画致命的缺点是,它只是看起来像一个动画而已,本质上view还是原来那样
属性动画于api11被引入,我们可以通过开源动画库nineoldandroids来兼容以前的版本.nineoldandroids 在aip11以前是通过代理view动画来实现,所以在api11以前它本质上还是view动画.
属性动画是通过操纵对象的属性来实现的,只要对象有这个属性,就能实现动画效果.默认间隔时间为300 ms,帧率为10 ms/帧
ObjectAnimator
动态使用
private void singleAnimator() {
ObjectAnimator backgroundColor = ObjectAnimator.ofInt(btn, "backgroundColor" , 0xFFFF8080 , 0xFF888888 );
backgroundColor.setDuration(3000 );
backgroundColor.setEvaluator(new ArgbEvaluator());
backgroundColor.setRepeatCount(ValueAnimator.INFINITE);
backgroundColor.setRepeatMode(ValueAnimator.REVERSE);
backgroundColor.start();
}
private void setAnimator() {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether
(ObjectAnimator.ofFloat(btn, "rotationX" , 0 , 360 )
, ObjectAnimator.ofFloat(btn, "rotationY" , 0 , 360 )
, ObjectAnimator.ofFloat(btn, "scaleX" , 1f , 1.5f )
,ObjectAnimator.ofFloat(btn, "scaleX" , 1f , 1.5f ,1f )
,ObjectAnimator.ofFloat(btn, "scaleY" , 1f , 0.5f ,1f )
,ObjectAnimator.ofFloat(btn, "translationX" , 1f ,300f ,0 )
);
animatorSet.setDuration(3000 ).start();
}
静态使用
创建animator目录
<set xmlns:android ="http://schemas.android.com/apk/res/android" >
<objectAnimator
android:duration ="1000"
android:propertyName ="translationX"
android:repeatCount ="0"
android:repeatMode ="restart"
android:startOffset ="15"
android:valueFrom ="1"
android:valueTo ="100"
android:valueType ="floatType" />
</set >
private void xml () {
AnimatorSet animator = (AnimatorSet) AnimatorInflater.loadAnimator(this , R.animator.object_animator);
animator.setTarget(btn);
animator.start();
}
<Set >对应AnimatorSet
android :ordering :有两个可选值.together ,动画集合中的子动画同时播放.sequentially ,前后顺序播放.
<objectAnimator >对应ObjectAnimator
android :propertyName ,表示属性动画作用对象的属性的名称;
android :duration ,表示动画的时长
android :valueFrom ,表示属性的起始值
android :valueTo
android :startOffset ,表示动画开始的延迟时间
android :repeatCount ,表示动画的重复次数.默认0,-1 表示无限循环
android :repeatMode ,表示动画的重复模式
android :valueType ,表示属性值的单位或类型,如果是颜色则不需要处理,自动会颜色进行判断
<animator >对应ValueAnimator
除了没有propertyName 其余属性都和object 相同.
属性动画的事件监听
public void setAnimatorListener (Animator animator){
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart (Animator animator) {
}
@Override
public void onAnimationEnd (Animator animator) {
}
@Override
public void onAnimationCancel (Animator animator) {
}
@Override
public void onAnimationRepeat (Animator animator) {
}
});
}
ValueAnimator
是ObjectAnimator的父类,比objectanimator更为强大,但使用也更复杂;
ObjectAnimator生效的要求为:
1 .object必须提供set XXX(),在没有传递初始值的时候必须额外提供getXXX().
2 .对属性的改变必须能通过某种途径反应出来,比如使ui改变等等
例如,Button有getWidth(确实是获取view的宽度)和set Width()(但set Width不是改变view的宽度,就是这么奇葩)方法,但它是由View的子类TextView提供的用于改变tv的最大宽度和最小宽度,并不是我们理解上的视图上的宽度,所以objectanimator无效.
解决办法:
1 .在有条件的情况下,加上getset方法
2 .使用包装类包装需要改变的view(推荐)
3 .使用ValueAnimator
静态使用
同objectanimator,在set 中item 中使用<animator>即可
动态使用
private void valueAnimator () {
ValueAnimator ofInt = ValueAnimator.ofInt(0 ,100 );
ofInt.setDuration(3000 );
ofInt.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
private IntEvaluator mEvaluator=new IntEvaluator();
@Override
public void onAnimationUpdate (ValueAnimator valueAnimator) {
Integer animatedValue = (Integer) valueAnimator.getAnimatedValue();
float animatedFraction = valueAnimator.getAnimatedFraction();
Integer evaluate = mEvaluator.evaluate(animatedFraction, 0 , 300 );
btn_value.getLayoutParams().width=evaluate;
btn_value.requestLayout();
}
});
ofInt.start();
}
注意事项
1 .注意OOM
2 .注意内存泄漏,属性动画中无限循环的,需要在页面退出时及时处理.View动画则没有该问题
3 .兼容性,在3.0 以下,兼容性需要小心处理
4 .View动画而能会导致set Visible()无效,可以调用view.clearAnimation()后set Visible()即可
5 .不要使用px
6.3 .0 以下的平台,无论是属性动画还是view动画,都是不能点击的 .
7 .请开启硬件加速