您的位置:首页 > 移动开发 > Android开发

android动画的使用(上-基本用法)

2017-02-22 10:14 525 查看

动画介绍

要开发一个优秀的app,除了功能强大以外,还得有优秀的UI设计,那么,掌握自定义View以及动画是非常有必要的,今天就来讲讲动画的使用。

Android的动画可以分为三种:View动画、帧动画和属性动画。

动画介绍
View动画
xml中定义View动画

完全用代码创建View动画

View动画监听器

自定义动画

帧动画

属性动画
ValueAnimator
xml实现ValueAnimator

代码实现ValueAnimator

ObjectAnimator
xml实现ObjectAnimator

代码实现ObjectAnimator

AnimatorSet
xml实现AnimatorSet

代码实现AnimatorSet

PropertyValueHolder

animate方法

属性动画的监听器

总结

View动画

View动画又叫做补间动画,它有四种默认动画效果:

平移(Translate)

缩放(Scale)

旋转(Rotate)

透明度(Alpha)

同时,它支持自定义动画,这个我们后面会将。

使用View动画也非常简单,主要有2种使用方式:

1. 在xml中定义动画,在代码中调用;

2. 完全用代码来写。

我们先来看下第一种使用方式

xml中定义View动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:duration="5000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:shareInterpolator="true">

<alpha
android:fromAlpha="0.5"
android:toAlpha="1">
</alpha>

<scale
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="0"
android:pivotY="0"
android:toXScale="2"
android:toYScale="2">
</scale>

<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="100"
android:toYDelta="100">
</translate>

<rotate
android:fromDegrees="0"
android:pivotX="0"
android:pivotY="0"
android:toDegrees="360">
</rotate>
</set>


set标签用于一系列动画组合,在后面的属性动画里我们也会用到。其中

android:duration代表动画时长;

android:fillAfter表示动画结束后View是否停留在结束位置,true表示停留在结束位置;

android:interpolator是指插值器,我们后面再讲;

android:shareInterpolator表示所有动画是否共享一个插值器,true表示共享,false表示不共享,这时需要自己给每个动画设置插值器。

关于set标签有2个属性是需要注意的:

android:repeatMode有restart和reverse,分别表示连续重复和逆向重复。

android:repeatCount表示重复的次数。

这两个属性一定要注意,在xml的set中使用是无效的,在单独的View动画中使用是有效的。

在代码中要调用这个动画也非常简单:

Animation animation = AnimationUtils.loadAnimation(
AnimationActivity.this, R.anim.test_animation);
v.startAnimation(animation);//v此时代表一个button


下面看看效果:



就两行代码即可使用,如果是单独一个一个写animation而不是用set标签的,调用起来也非常方便,代码如下:

AnimationSet animationSet = new AnimationSet(true);

Animation anim1 = AnimationUtils.loadAnimation(AnimationActivity.this,
R.anim.test_animation_alpha);
animationSet.addAnimation(anim1);

Animation anim2 = AnimationUtils.loadAnimation(AnimationActivity.this,
R.anim.test_animation_translate);
animationSet.addAnimation(anim2);

animationSet.setDuration(2000);
animationSet.setFillAfter(true);
v.startAnimation(animationSet);


下面看看完全用代码如何写。

完全用代码创建View动画

直接上代码了:

AnimationSet animationSet = new AnimationSet(true);
AlphaAnimation anim1 = new AlphaAnimation(0.5f, 1f);
animationSet.addAnimation(anim1);

TranslateAnimation anim2 = new TranslateAnimation(0f, 300f, 0f, 300f);
animationSet.addAnimation(anim2);

ScaleAnimation anim3 = new ScaleAnimation(1f, 2f, 1f, 2f,
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f);
animationSet.addAnimation(anim3);

animationSet.setDuration(2000);
animationSet.setFillAfter(true);
v.startAnimation(animationSet);


效果我就不展示了,其中要注意的是ScaleAnimation和RotateAnimation有一个旋转轴点的概念pivotX和pivotY,默认的旋转点都是控件的(0,0)处,上面代码我使用的就是左上角即(0,0)的点,具体效果大家可以自己去试试。

View动画监听器

AnimationListener,主要监听View动画的开始、重复以及结束这三个过程,使用也非常简单,如下代码所示:

animationSet.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
Toast.makeText(AnimationActivity.this, "动画开始了", Toast.LENGTH_SHORT).show();
}

@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationEnd(Animation animation) {
Toast.makeText(AnimationActivity.this, "动画结束了", Toast.LENGTH_SHORT).show();
}
});


自定义动画

创建自定义动画非常简单,只需要实现applyTransformation和initialize方法即可。在applyTransformation中完成自己想要实现的效果,在initialize中做一些初始化操作。

下面我们来看下这两个方法。

* @param width Width of the object being animated
* @param height Height of the object being animated
* @param parentWidth Width of the animated object's parent
* @param parentHeight Height of the animated object's parent
*/
public void initialize(int width, int height, int parentWidth, int parentHeight){
}


介绍都有,四个参数,子控件长宽和父控件长宽。

* @param interpolatedTime The value of the normalized time (0.0 to 1.0)
*        after it has been run through the interpolation function.
* @param t The Transformation object to fill in with the current
*        transforms.
*/
protected void applyTransformation(float interpolatedTime, Transformation t) {
}


第一个参数interpolatedTime为0.0~1.0的递增值,随着动画执行时间逐渐增大;而t可以用来获取初始变换矩阵Matrix,我们就是根据这个矩阵值的改变来进行动画的,并且往往会使用到Camera这个类来执行一些3D效果,下面我们看下代码实现。

/**
* Created by bellnett on 2017/2/24.
*/

public class CustomAnimation extends Animation {

private Camera mCamera;
private float mCenterHeight;
private float mCenterWdith;

@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);

mCamera = new Camera();
setFillAfter(true);
mCenterHeight = height / 2;
mCenterWdith = width / 2;
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);

Matrix matrix = t.getMatrix();

mCamera.save();
mCamera.translate(0,0,interpolatedTime * 300);
mCamera.rotateY(interpolatedTime * 360);
mCamera.getMatrix(matrix);
mCamera.restore();

/* 以高度的中心点作为旋转中心 */
matrix.preTranslate(0,-mCenterHeight);
matrix.postTranslate(0,mCenterHeight);
}
}


主要做了2个操作,一个是向Z轴平移了300,另一个是绕Y轴旋转360度,至于这个camera的类,它的坐标系是3D坐标,这里就不介绍了,感兴趣的可以自己去研究。要注意的还有最后两行代码,还记得之前我们说过,scale和rotate动画的旋转点初始化都是(0,0),这里通过preTranslate和postTranslate将按钮先向上平移一半的高度,等动画结束时再平移回来,这样的效果就相当于围绕(0,height/2)这个点做动画。

使用也非常简单

CustomAnimation customAnimation = new CustomAnimation();
customAnimation.setDuration(2000);
customAnimation.setInterpolator(new LinearInterpolator());
view.startAnimation(customAnimation);


效果如下:



帧动画

帧动画的实现也非常简单,归为一下三部:

在drawable中实现animation-list

给控件设置背景资源setBackgroundResource

实现AnimationDrawable对象

开启动画

xml代码实现:

<?xml version="1.0" encoding="utf-8"?>
<animation-list
android:oneshot="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/a1" android:duration="1000"></item>
<item android:drawable="@drawable/a2" android:duration="1000"></item>
<item android:drawable="@drawable/a3" android:duration="1000"></item>
</animation-list>


其中oneshot这个属性表示动画的自动执行,false表示循环播放;true表示只执行一次,并且停留在最后一帧上。

调用代码实现:

view.setBackgroundResource(R.drawable.animation_drawable_test);
AnimationDrawable animationDrawable = (AnimationDrawable) view.getBackground();
animationDrawable.start();


效果如下:



属性动画

属性动画是在android 3.0即API 11之后才出现的,因此要兼容低版本的android系统,必须使用nineoldandroids这个动画库来兼容,这个兼容库我就不说了,感兴趣的自己去下载试试。属性动画常用的有以下三个类:ValueAnimator、ObjectAnimator以及AniamtorSet,下面我们分别讲解。

ValueAnimator

ValueAnimator从字面上看就能知道,它是一个值动画,也就是说,它不会包含具体的动画效果,只是值的变化,具体的动画需要我们根据这个值来做。那么如何使用这个ValueAnimator呢,我们分别从xml和用代码建立来讲解。

xml实现ValueAnimator

(1)首先是总布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="TestValueAnimator"
android:text="testValueAnimator"
android:textAllCaps="false">
</Button>

<ImageView
android:id="@+id/animatorIv"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/a1" />

</LinearLayout>


很简单,一个按钮,一个图,用按钮来完成图的属性动画。

(2) 然后是动画的xml:

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="50"
android:valueTo="300"
android:valueType="intType" >

</animator>


非常简单,值从50~300变化。

(3)下面我们看看在代码中如何调用:

public void TestValueAnimator(final View v) {
ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater
.loadAnimator(AnimatorActivity.this, R.animator.test_animator);
valueAnimator.setDuration(2000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setTarget(iv1);
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.setRepeatCount(2);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
iv1.getLayoutParams().width = value;
iv1.getLayoutParams().height = value;
iv1.requestLayout();
}
});
}


(4)看下效果图:



前面说过了,ValueAnimator只是值变化的动画,没有具体的动画效果,因此,必须实现AnimatorUpdateListener这个监听类,来监听值得变化,然后根据值的变化来实现具体的动画,在这个例子中是实现图的长宽变化。

代码实现ValueAnimator

代码实现更加方便,请看如下代码:

ValueAnimator valueAnimator = ValueAnimator.ofInt(50,300);


一句代码就能实现之前(2)中定义的动画,而且直接可以使用,不需要再调用AnimatorInflater类的loadAnimator()方法来载入动画。下面的调用和(3)中的一样,就不重复写了。

ObjectAnimator

ObjectAnimator就是可以直接实现属性动画的类了,相比ValueAnimator要使用地更加频繁,更加好用,下面我们看看ObjectAnimator的使用,也是分xml和代码实现。

xml实现ObjectAnimator

(1)总布局代码不变,直接上动画的xml实现:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="translationX"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType" >

</objectAnimator>


有两点要注意:

1. 其中的valueType使用的是浮点数类型,主要是ImageView的setTranslationX方法的参数是浮点数类型的,因此我们要灵活运用。

2. 相比ValueAnimator,ObjectAnimator只比它多了一个android:propertyName参数,至于这个参数怎么填,我们可以根据我们需要设置动画的控件,输入setXXX来查看,后面XXX就是这个属性所填写的值。

(2)代码调用:

ObjectAnimator objectAnimator = (ObjectAnimator) AnimatorInflater
.loadAnimator(AnimatorActivity.this, R.animator.test_animator);
objectAnimator.setDuration(2000);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.setRepeatCount(2);
objectAnimator.setTarget(iv1);
objectAnimator.start();


和ValueAnimator差不多,只是不需要监听AnimatorUpdateListener,就能实现ImageView从0~300的X轴变化。

(3)效果图:



代码实现ObjectAnimator

代码实现也非常的简单:

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv1,
"translationX", 0f, 300f);
objectAnimator.setDuration(2000);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.setRepeatCount(2);
objectAnimator.start();


和ValueAnimator有所不同的是,在使用ofXXX方法时可以直接设定target,而无需调用setTarget()方法了,具体效果和上面的相同。

AnimatorSet

xml实现AnimatorSet

(1)总布局不变,我们看下xml中AnimatorSet的实现,和AnimationSet类似,要注意的是有一个android:ordering属性,它有两个值together和sequentially,前者代表动画一起执行;后者表示动画按顺序执行:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">

<objectAnimator
android:propertyName="translationX"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType">

</objectAnimator>

<objectAnimator
android:propertyName="translationY"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType">

</objectAnimator>
</set>


(2)然后是代码的调用,和ValueAnimator以及ObjectAnimator是一样的,只是没法设置repeatMode和repeatCount了:

AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(AnimatorActivity.this, R.animator.test_animator);
animatorSet.setDuration(2000);
animatorSet.setTarget(iv1);
animatorSet.start();


(3)看下效果:



代码实现AnimatorSet

代码实现也很方便:

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(2000);

ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(iv1,"translationX",0f,300f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(iv1,"translationY",0f,300f);

animatorSet.playTogether(objectAnimator1,objectAnimator2);
animatorSet.start();


效果和上面是一样的,playTogether对应xml中的together;还有一个方法playSequentially对应xml中的sequentially。

PropertyValueHolder

PropertyValueHolder的使用是类似AnimatorSet的,不过它只能同步执行动画,没法按顺序执行动画。所以当要同时执行多个动画的时候,PropertyValueHolder也是个不错的选择。下面看代码:

PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("translationX",0f, 300f);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("translationY",0f, 300f);
ObjectAnimator.ofPropertyValuesHolder(iv1, propertyValuesHolder1, propertyValuesHolder2)
.setDuration(2000).start();


效果和同步执行的AnimatorSet是一样的,效果图我就不贴了。

animate方法

animate是ViewPropertyAnimator类的一个方法,它支持链式操作,使用上算是属性动画的一种简便方式,请看如下代码:

iv1.setPivotX(0f);
iv1.setPivotY(0f);
iv1.invalidate();

iv1.animate()
.scaleX(2f)
.scaleY(2f)
.alpha(0.5f)
.setDuration(2000)
.withStartAction(new Runnable() {
@Override
public void run() {

}
})
.withEndAction(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
iv1.setAlpha(1.0f);
iv1.setScaleX(1f);
iv1.setScaleY(1f);
}
});
}
})
.start();


其中要注意的有以下几点:

属性动画默认旋转点是中心点,因此要改变旋转点直接使用setPivotX和setPivotY,然后显示调用以下invalidate。

withStartAction和withEndAction都是API16添加进来的,因此如果要使用这两个方法必须api要在16及以上。

ViewPropertyAnimator也支持AnimatorListener和AnimatorUpdateListener,这个监听器我们在下面会讲。

下面看下效果图:



属性动画的监听器

属性动画一共有2个监听器:

AnimatorListener

-AnimatorListenerAdapter

AnimatorUpdateListener

AnimatorListener一共有4个方法,start、end、cancel以及repeat,如果直接实现这个监听器就得重写这4个方法,不过,AnimatorListener提供了一个AnimatorListenerAdapter适配器,如果实现这个适配器的话,就可以有选择的重写以上4个方法。

AnimatorUpdateListener我们在上面讲解ValueAnimator时已经用过了,没看的请翻到上面。

下面看下代码:

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv1,"translationX",0f,300f);
objectAnimator.setDuration(2000);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.start();
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {

}

@Override
public void onAnimationEnd(Animator animation) {

}

@Override
public void onAnimationCancel(Animator animation) {

}

@Override
public void onAnimationRepeat(Animator animation) {

}
});

objectAnimator.addListener(new AnimatorListenerAdapter() {

@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});

objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {

}
});


总结

最后我们总结一下:

Animation对应View动画;Animator对应Property动画。

View动画使用之后,按钮的位置改变了,但是点击的位置还是原来的位置;属性动画使用之后,不仅位置改变,连点击的位置也会随着改变。因此,View动画适合做一些视觉效果;属性动画适合做一些交互式动画。

使用旋转和缩放时要注意旋转轴点,View动画默认是(0,0);而属性动画默认是控件的中心点。

帧动画应尽量避免使用,图片一多就容易引起OOM。

不管是View动画还是属性动画,单个动画都可以设置循环模式和循环次数,当多个动画组合时没法直接设置循环模式和循环次数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息