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

android开发艺术探索(七)

2016-08-30 09:48 441 查看

Android动画深入分析

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

View动画

View动画的作用对象是View,它支持四种动画效果,分别是平移动画(TranslateAnimation)、缩放动画(ScaleAnimation)、旋转动画(RotateAnimation)、和透明度动画(AlphaAcnimation)。除此之外,还提供了动画集合AnimationSet动画集合,混合使用多种动画。

使用动画方式:

1、代码中加载xml动画文件。我们再res/anim文件夹下新建view_alpha.xml文件。

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0"
android:toAlpha="1"
>
</alpha>


在代码中加载此动画:

AlphaAnimation alpha= (AlphaAnimation) AnimationUtils.loadAnimation(MainActivity.this,R.anim.view_alpha);
//设置动画持续时间
alpha.setDuration(1000);
//View动画开始
ivPhoto.startAnimation(alpha);


2、在代码中构建动画

/**透明度动画,第一个参数为起始透明度
* 第二个参数为结束时透明度
* */
AlphaAnimation alpha=new AlphaAnimation(0,1);
//设置动画持续时间
alpha.setDuration(1000);
//View动画开始
ivPhoto.startAnimation(alpha);


我们先简单看一下动画的固定语法:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true"
android:duration="1000"
android:fillAfter="true"
>
<alpha
android:fromAlpha="0"
android:toAlpha="1"></alpha>

<scale
android:fromXScale="0.5"
android:fromYScale="0.5"
android:pivotX="0"
android:pivotY="0"
android:toXScale="1.5"
android:toYScale="1.5"></scale>
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="100"
android:toYDelta="0"></translate>
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="225"></rotate>
</set>


set标签,对应AnimationSet类,表示动画合集。

interpolator:表示动画集合所采用的插值器,插值器影响动画的速度。

shareInterpolator:表示动画集合是否共享同一个插值器。

duration:表示动画的持续时间。

fillAfter:动画结束后,View是否停留在结束位置,true表示View停留在结束位置,false则不停留。

translate标签:对应TranslateAnimation类,它可以使一个view在水平和竖直方向完成平移的动画效果。

fromXDelta:平移初始位置的x值

fromYDelta:平移初始位置的y值

toXDelta:平移结束位置的x值。

toYDelta:平移结束位置的y值。

scale标签:对应ScaleAnimation类,他可以使View具有放大或者缩小的动画效果。

fromXScale:水平方向缩放的起始值。

toXScale:水平方向缩放的结束值。

fromYScale:竖直方向缩放的起始值。

toYScale:竖直方向缩放的结束值。

pivotX:缩放的轴点x坐标,它会影响缩放的效果。

pivotY:缩放的轴点y坐标,会影响缩放的效果。

默认情况下,缩放的轴点是View的中心点

rotate:旋转动画,对应RotateAnimation,它可以使View具有旋转的动画效果。

fromDegrees:旋转开始的角度。

toDegrees:旋转结束的角度。

pivotX:旋转的轴点的x坐标。

pivotY:旋转的轴点的y坐标。

alpha:透明度动画,对应AlphaAnimation,可以改变View的透明度。

fromAlpha:表示透明度的起始值。

toAlpha:表示透明度的结束值。

代码生成:

1、透明度动画

/**透明度动画,第一个参数为起始透明度
* 第二个参数为结束时透明度
* */
AlphaAnimation alpha=new AlphaAnimation(0,1);
alpha.setDuration(1000);
ivPhoto.startAnimation(alpha);


2、旋转动画

/**参数一:代码起始角度
* 参数二:代码结束角度
* 参数三和参数四为大妈旋转中心点坐标的x、y值
* */
RotateAnimation ra=new  RotateAnimation(0,360,100,100);
ra.setDuration(1000);
ivPhoto.startAnimation(ra);


同时也可以设置参考系为自身中心点:

RotateAnimation ta=new RotateAnimation(0,360,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
ta.setDuration(1000);
ivPhoto.startAnimation(ta);


3、平移动画

TranslateAnimation ta=new TranslateAnimation(0,200,0,300);
ta.setDuration(1000);
ivPhoto.startAnimation(ta);


4、缩放动画

ScaleAnimation sc=new ScaleAnimation(0,2,0,2);
sc.setDuration(1000);
ivPhoto.startAnimation(sc);


同时也可以设置缩放的中心点:

ScaleAnimation sc=new ScaleAnimation(0,2,0,2
, Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
sc.setDuration(1000);
ivPhoto.startAnimation(sc);


5、动画合集:

通过AnimationSet,可以将动画以组合的形式展现出来:

AnimationSet set=new AnimationSet(true);
set.setDuration(1000);

AlphaAnimation aa=new AlphaAnimation(0,1);
aa.setDuration(1000);
/**将此动画加入到集合中*/
set.addAnimation(aa);

TranslateAnimation ta1=new TranslateAnimation(0,100,0,200);
ta1.setDuration(1000);
/**将此动画加入到集合中*/
set.addAnimation(ta1);

ivPhoto.startAnimation(set);


对于动画时间,android也提供了对应的监听回调,要添加相应的监听方法:

sc.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
/**动画开始*/
}

@Override
public void onAnimationEnd(Animation animation) {
/**动画结束*/
}
@Override
public void onAnimationRepeat(Animation animation) {
/**动画结束*/
}
});


自定义View动画

除了系统提供的动画之外,我们还可以自定义动画。

1:继承Animation抽象类,重写initialize和applyTransformation方法

2:在initialize方法中进行初始化操作

3:在applyTransformation方法总进行相应的矩阵变换,一般采用Carmera简化矩阵变换。

帧动画

帧动画是顺序播放一组预先定义好的图片,类似于电影播放。系统提供了一个类AnimationDrawable来使用帧动画。

在res/drawable下新建动画view_animation_drawable.xml文件,如下:

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


然后将上述的Drawable作为View的背景并通过Drawable来播放动画即可:

ivPhoto.setBackgroundResource(R.drawable.view_animation_drawable);
AnimationDrawable ad= (AnimationDrawable) ivPhoto.getBackground();
ad.start();


注意:帧动画比较容易引起OOM,使用时尽量避免使用尺寸较大的图片。

View动画的特殊使用场景

View动画可以在一些特殊的场景下使用:

Viewgroup中可以控制子元素的出场效果

在Activity中可以实现不同的Activity之间的切换效果。

LayoutAnimation

LayoutAnimation作用于Viewgroup,为ViewGroup指定一个动画,使它的子元素出场时具有一定的动画效果。LayoutAnimation也是一个View的动画。

使用步骤:

Step1:定义LayoutAnimation

在res/anim下新建view_layout_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/anim_item"
>
</layoutAnimation>


属性含义:

delay:表示子元素开始动画的时间延迟。

android:animationOrder:表示子元素动画的顺序,有三种选项:noraml、reverse和random其中normal表示顺序显示;reverse表示逆向显示;random则是随机播放入场动画。

android:animation:为子元素指定具体的入场动画

Step2:为子元素指定具体的入场动画

在res/anim下新建anim_item.xml文件

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:shareInterpolator="true">
<alpha
android:fromAlpha="0"
android:toAlpha="1"></alpha>

<translate
android:fromXDelta="500"
android:toXDelta="0"
></translate>
</set>


Step3:为ViewGroup指定android:animation=”@anim/anim_item”属性

<ListView
android:id="@+id/lv_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/view_layout_animation"
></ListView>


除了在XML中指定LayoutAnimation之外,还可以通过LayoutAnimationController来实现。

Animation animation= AnimationUtils.loadAnimation(this,R.anim.anim_item);
LayoutAnimationController controller=new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
lvList.setLayoutAnimation(controller);


Activity的切换效果

Activity有默认的切换效果,但是这个效果我们是可以自定义的,主要用到overridePendingTransition(int enterAnim, int exitAnim)这个方法。注意:次方法必须在startActivity(intent)或者finish()之后调用才能生效。

enterAnim:activity被打开时,所需的动画资源id;

exitAnim:activity被暂停时,所需的动画资源id;

例如:

Intent intent=new Intent(this,ActivityA.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_right_in,R.anim.slide_right_out);


右侧进入动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="100.0%p"
android:toXDelta="0.0" />
</set>


右侧移出动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0.0"
android:toXDelta="100.0%p" />
</set>


Android属性动画分析

对于View动画来说,动画改变的只是显示,并不能影响时间,因此在3.0之后,android退出了属性动画。

ObjectAnimator

ObjectAnimator是属性动画框架中最重要的实行类。我们可以通过ObjectAnimator的静态工厂类获取ObjectAnimator对象。

我们来实现一个简单的平移动画:

/**第一个参数为要操作的View,第二个参数为要操作的属性,而最后一个参数是一个可变数组参数*/
ObjectAnimator animator=ObjectAnimator.ofFloat(ivPhoto,"translationX",300);
animator.setDuration(300);
animator.start();


PropertyValuesHolder

类似视图动画中的AnimationSet,在属性动画中,如果针对于同一个对象的多个属性,需要同时作用多种动画,可以使用PropertyValuesHolder来实现。

比如平移的时候进行动X、Y轴的动画缩放,如下:

PropertyValuesHolder pv1=PropertyValuesHolder.ofFloat("translationX",300f);
PropertyValuesHolder pv2=PropertyValuesHolder.ofFloat("scaleX",1f,0,1f);
PropertyValuesHolder pv3=PropertyValuesHolder.ofFloat("scaleY",1f,0,1f);
ObjectAnimator.ofPropertyValuesHolder(ivPhoto,pv1,pv2,pv3)
.setDuration(1000).start();


ValueAnimator

ValueAnimator在属性动画中占有很重要的地位,ObjectAnimation也是继承自ValueAnimator;

ValueAnimator本身并不提供任何动画效果,它更像是一个数值发生器,用来产生具有一定规律的数字,从而让调用者来实现动画的实现过程。

使用方法:通常情况下,在ValueAnimator的AnimatorUpdateListener中监听数值的变换,从而完成动画的变换。

ValueAnimator animator1=ValueAnimator.ofFloat(0,100);
animator1.setTarget(ivPhoto);
animator1.setDuration(1000).start();
animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Float value= (Float) valueAnimator.getAnimatedValue();
}
});


动画事件的监听

一个完整个的动画具有Start、Repeat、End、Cancel四个过程,通过Android提供了接口,可以很方便的监听事件:

ObjectAnimator obj1=ObjectAnimator.ofFloat(ivPhoto,"alpha",0.5f);
obj1.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) {
/**动画重复*/
}
});


我们可以使用AnimatorListenerAdapter进行事件筛选。

obj1.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});


AnimatorSet

动画合集,和PropertyValuesHolder类似,但是AnimationSet可以提供更精确的顺序控制。

ObjectAnimator as1=ObjectAnimator.ofFloat(ivPhoto,"translationX",300f);
ObjectAnimator as2=ObjectAnimator.ofFloat(ivPhoto,"scaleX",1f,0,1f);
ObjectAnimator as3=ObjectAnimator.ofFloat(ivPhoto,"scaleY",1f,0,1f);
AnimatorSet set=new AnimatorSet();
set.setDuration(1000);
set.playTogether(as1,as2,as3);
set.start();


在XML中使用属性动画

在res/animator文件夹下新建scalex.xml文件

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


在代码中加载属性动画:

Animator at= AnimatorInflater.loadAnimator(this,R.animator.scalex);
at.setTarget(ivPhoto);
at.start();


View的animate方法

3.0之后,googel给View增加了animate方法来直接驱动属性动画,代码如下:

ivPhoto.animate()
.alpha(0).y(300)
.setDuration(300)
.withStartAction(new Runnable() {
@Override
public void run() {
}
})
.withEndAction(new Runnable() {
@Override
public void run() {

}
}).start();


理解插值器和估值器

TimeInterpolator中文翻译为事件插值器,作用是根据时间流逝的百分比来计算出当前属性值改变的百分比。

备注:

自定义插值器需要实现Interpolator或者TimeInterpolator,自定义估值算法需要实现TypeEvaluator,另外就是如果要对其他类型(非int、float、Color)做动画,那么必须奥自定义类型估值算法。

属性动画的监听器

属性动画提供了监听器用于监听动画的播放过程,主要有两个接口:

AnimatorListener和AnimatorUpdateListener;

前面已经介绍过了,这里就不说了。

对任意属性做动画

注意:在使用ObjectAnimator 的时候,需要操作的属性必须具有get和set方法,不然ObjectAnimator 就无法起作用。

如果一个属性没有get和set方法,如何来使用?

google在应用曾提供了两种方案,

1、通过自定义一个属性类,或者包装类,来简介的给这个属性增加get和set方法,

2、通过ValueAnimation来实现。

(1)使用包装类

public class WrapperView {

private View mTarget;

public WrapperView(View target){
mTarget=target;
}

public int getWidth(){
return mTarget.getLayoutParams().width;
}

public void setWidth(int width){
mTarget.getLayoutParams().width=width;
mTarget.requestLayout();
}
}


通过以上代码,就给一个属性包装了一层,并且给他提供了get、set方法。使用时,只需要操纵包专类就可以间接地调用到get、set方法了。

WrapperView view=new WrapperView(ivPhoto);
ObjectAnimator.ofFloat(view,"width",500).setDuration(5000).start();


(2)采用ValueAnimation,监听动画过程,自己实现属性的改变

ValueAnimation可以对一个值做动画,然后我们可以监听其动画过程,在动画过程中修改我们对象的属性值。

属性动画的工作原理

属性动画要求作用的对象提供属性的set方法,属性动画根据你传递的该属性的初始值和最终值,以动画的效果多次去调用set方法。每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。

如果动画的时候没有传递初始值,那么还要提供set方法,因为系统要去获取属性的初始值。

使用动画的注意事项

(1)OOM问题

这个问题主要出现在帧动画中,当图片数量较多且图片较大时就容易出现OOM,尽量避免使用帧动画。

(2)内存泄漏

在属性动画中有一类无线循环的动画,这类动画需要在activity退出时及时停止,否则将导致actiivty无法释放而造成内存泄漏。

(3)兼容性问题

动画在3.0以下的系统上有兼容性问题,在某些特殊场景可能无法正常工作,因此要做好适配工作。

(4)View动画的问题

View动画是对View的影响做动画,并不是真正的改变View的状态,因此会出现东湖完成后无法隐藏的现象,即setVisibility(View.GONE)失效,这个时候要调用View.clearAnimation()清除View动画即可解决此问题。

(5)不要使用px

在进行动画的过程中,要尽量使用dp,使用平px会在不同的设备上有不同的效果。

(6)动画元素的交互

将View平移后,在android3.0以前的系统上,不管是View动画还是属性动画,新位置均无法触发单击事件,老位置仍然可以触发单击事件。

(7)硬件加速

使用动画过程中,建议开启硬件加速,会提高动画的流畅性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: