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

Android Animation

2016-03-12 16:28 423 查看
1、Android Animation设计模式

Android的架构中用了很多的设计模式,Android的动画模型感触颇深,笔者之前开发过C++的动画模型,动画的模型和具体的元素耦合在一起,代码混乱,难以维护,使用复杂度高,可复用性低。



动画自成体系,和view通过接口交互,既具备模块隔离性,又保证了充分的扩展性。

至于实现view动画的细节实现,有机会还需要仔细研究下,刚入手重点还放在应用层面。

2、Android动画

Android动画整体可范围三类:view animation,drawable animation,property animation

2.1 view animation

View Animation只能应用于view对象,并且要注意的一点,对于View Animation,它只是改变了View对象绘制的位置,并没有改变View对象本身。比如,你定义了一个View,属性为(x:100,y:100,width:100,height:100),有一个动画使其变为(x:100,y:100,width:50,width:50),在动画过程中Button的点击区域仍然是(x:100,y:100)->(200,200).

View Animation支持支持四种动画效果,TranslateAnimation,ScaleAnimation,RotateAnimation,AlphaAnimation。动画的定义既可以通过XML方式来定义,也可以通过动态代码方式来创建。

单个View可以同时设置多个动画,默认多个动画是同时进行的,可以通过startOffset属性设置各个动画的开始偏移(开始时间)来达到动画顺序播放的效果。

通过XML方式定义View动画,需要在res/anim文件夹内创建xml文件,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator"
android:duration="150"
android:fromDegrees="0.0"
android:toDegrees="-225.0"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:fillAfter="true"
android:fillEnabled="true">

</rotate>


在代码中,加载XML文件实例化Animation,指定给指定的View即可。

Button mButton = (Button)findViewById(R.id.button1);
Animation animation = AnimationUtils.loadAnimation(this,
R.anim.rotate_button_in);
mButton.startAnimation(animation);


XML文件的根元素可以为:,,,,(表示以上几个动画的集合,set可以嵌套,默认set内动画元素同时执行)

还可以通过代码方式定义动画

Button mButton = (Button)findViewById(R.id.button1);
AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
alphaAnimation.setDuration(200);
mButton.startAnimation(alphaAnimation);


2.2 Drawable Animation

Drawable Animation通过顺序播放一组图片来实现动画的效果,使用方法如下:

在res/drawable/目录下新建Drawable

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


调用逻辑如下:

Button mButton = (Button)findViewById(R.id.button1);
mButton.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable drawable = (AnimationDrawable)mButton.getBackground();
drawable.start();


2.3 属性动画

属性动画是API 11后引入的,它扩展了动画的作用对象,可以对任何对象做动画,同时扩展了动画效果,可以实现更为绚丽的效果。属性动画几乎无所不能,只有对象有这个属性,就可以针对它做动画。在API 11版本之前,可以采用开源动画库nineoldandroids兼容以前版本。

2.3.1 属性动画的基础用法

属性动画中比较常用的几个类:ValueAnimator、ObjectAnimator、AnimatorSet。

与View动画一样,属性动画也有两种创建方法:通过代码创建和通过XML创建。

1)实现button上下平移的动画。

Button aniBtn = (Button)findViewById(R.id.btn_anim);
ValueAnimator alphaAnim = ObjectAnimator.ofFloat(aniBtn, "translationY", 0,90);
alphaAnim.setDuration(5000);
alphaAnim.setRepeatCount(ValueAnimator.INFINITE);
alphaAnim.start();


2) 改变View的背景色,实现在3s内从0xFFFF8080到0xFF8080FF的渐变,动画会无限重复。

ValueAnimator colorAnim = ObjectAnimator.ofInt(customView, "backgroundColor",0xFFFF8080,0xFF8080FF);
colorAnim.setDuration(3000);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.setRepeatCount(ValueAnimator.INFINITE);
colorAnim.start();


3) 动画集合,5s内对View的旋转、平移、缩放和透明度都进行改变。

AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(customView, "rotationX", 0, 360);
ObjectAnimator.ofFloat(customView, "rotationY", 0, 180);
ObjectAnimator.ofFloat(customView, "translationX", 0, 90);
ObjectAnimator.ofFloat(customView, "translationY", 0, 90);
ObjectAnimator.ofFloat(customView, "scaleX", 1, 1.5f);
ObjectAnimator.ofFloat(customView, "scaleY", 1, 0.5f);
ObjectAnimator.ofFloat(customView, "alpha", 1, 0.25f,1);

);
set.setDuration(5000).start();


通过XML创建

属性动画需要定义在res/animator/目录下,格式如下:

<set android:ordering=["together"|"sequentially"]>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float|int|color"
android:valueTo="float|int|color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat|reverse"]
android:valueType=["intType|floatType"]/>

<Animator
android:duration="int"
android:valueFrom="float|int|color"
android:valueTo="float|int|color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat|reverse"]
android:valueType=["intType|floatType"]/>

<set>
...
</set>
</set>


使用属性动画的方式也很简单

AnimatorSet set=(AnimatorSet)AnimatorInflater.loadAnimator(customContext,R.anim.property_animator);
set.setTarget(mButton);
set.start();


2.3.2 属性动画的扩展

属性动画的Interpolator和TypeEvaluator很重要,通过自定义这两个接口可以实现千奇百怪的动画效果。

LinearInterpolator的源码:

public class LinearInterpolator implements Interpolator{

public LinearInterpolator(){
}

public LinearInterpolator(Context context, AttributeSet attrs)(){
}

public float getInterpolation(float input){
return input;
}
}


IntEvaluator的源码

public class IntEvaluator implements TypeEvaluator<Integer>{
public Integer evaluate(float fraction, Integer startValue, Integer endValue){
int startInt = startValue;
return (int)(startInt + fraction*(endValue-startValue))
}
}


属性动画还提供了AnimatorUpdateListener和AnimatorListener两个监听器,用来监听动画的播放过程。

AnimatorLister的定义如下:

public static interface AnimatorLister{
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
}


AnimatorUpdateListener的定义如下:

public static interface AnimatorUpdateListener{
void onAnimationUpdate(ValueAnimator animation);
}


2.3.3 对任意属性做动画

针对Object属性abc的属性动画要生效,必须同时满足两个条件:

1) Object必须要提供setAbc的方法,如果动画的时候没有传递初始值,还必须提供getAbc的方法,因为系统要去取Abc属性的初始值(该条不满足,程序直接crash)

2)Object的setAbc方法对属性abc的改变必须能够通过某种方式反映出来,比如会带来UI改变之类的(不满足这条,动画无效果但不会crash)

如何给对象属性添加set和get方法,官方文档提供三个解决方法:

1、如果有权限的话,给你的对象加上get和set方法;

简单有效,但往往我们没有权限。

2、用一个类包装原始对象,间接为其提供get和set方法;

private void performAnimate(){
ViewWrapper wrapper = new ViewWrapper(mButton);
ObjectAnimator.ofInt(wrapper,"width",500).setDuration(5000).start();
}

@override
public void onClick(View v){
if (v == mButton){
performAnimate();
}
}

private static class ViewWrapper {
private View mTarget;

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

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

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

}


3、采用ValueAnimator, 监听动画过程,自己实现属性的改变。

private void performAnimate(final View target, final int start, final int end){
ValueAnimator valueAnimator = ValueAnimator.ofInt(1,100);
valueAnimator.addUpdateListener(new AnimatorUpdateListener(){
private IntEvaluator mEvaluator = new IntEvaluator();

@override
public void onAnimationUpdate(ValueAnimator animator){
int currentValue = (Interge)animator.getAnimateValue();

float fraction = animator.getAnimateFraction();

target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);

target.requestLayout();
}
});

valueAnimator.setDuration(5000).start();
}

@override
public void onClick(View v){
if (v == mButton){
performAnimate(mButton,mButton.getWidth(),500);
}
}


参考资料:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: