Android应用中各式各样的交互界面能体现一个Android应用独特的设计理念,为应用增色不少。为了要实现这些效果就需要用到Android中关于动画的API,Android中的动画效果主要分为逐帧动画
、补间动画
、属性动画
。
逐帧动画的原理与电影的原理一样,都是把一连串的静态图片按顺序依次显示,利用“视觉暂留”使人感觉“动画”的错觉。
逐帧动画一般采用AnimationDrawable显示,并用XML文件定义资源
……………
定义的资源可以作为ImageView的资源文件使用:
ImageView image = (ImageView) findViewById(R.id.frame_animation);
//获取在布局文件中设置的动画文件
final AnimationDrawable anim = (AnimationDrawable)image.getDrawable();
//为ImageView设置点击事件,点击开始动画,再次点击停止动画
image.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(anim.isRunning())
{
anim.stop();
} else {
anim.start();
}
}
});
如果不使用XML文件定义资源,也可以通过在JAVA代码中创建AnimationDrawable类,调用addFrame(Drawable frame, int duration)
添加每一帧。
逐帧动画效果:
补间动画是只需指定开始状态与结束状态的“关键帧”,由系统根据配置计算出中间帧的一种动画。其本质上也是逐帧动画,只是不需要指定每一帧。Android使用Animation代表抽象的动画类,它包括如下几个子类:
Animation都需要指定动画持续时间。
//以图片中心为基准3秒内旋转9000度
RotateAnimation anim = new RotateAnimation(9000, 0, image.getWidth() / 2, image.getHeight() / 2);
anim.setDuration(3000);
image.setAnimation(anim);
//透明度由0到1
lphaAnimation anim = new AlphaAnimation(0, 1);
//由1倍缩放到3倍
ScaleAnimation anim = new ScaleAnimation(1, 3, 1, 3, image.getWidth() / 2, image.getHeight() / 2);
//从(0, 0)移动到(300, 300)
TranslateAnimation anim = new TranslateAnimation(0, 300, 0, 300);
为了控制系统在关键帧之间需要补入多少帧,具体在动画运行时何时补入,需要借助Interpolator
。
Interpolator根据特定算法计算出整个动画所需动态插入帧的密度和位置,控制动画的变化速度,如匀速变化、加速、减速、抛物线速度等。Interpolator为一个接口,它的实现类有:
补间动画一般在XML文件中用元素定义(可混合多种动画),并在JAVA代码中用AnimationUtils.loadAnimation(Context context, int Id)
加载自定义补间动画。
自定义补间动画需继承Animation类,并重写该类的 applyTransformation(float interpolatedTime, Transformation t)
方法,其中参数说明如下:
为了控制图片或View进行三维空间的变换,还需要借助于Android提供一个Camera,Camera提供了如下常用方法:
实现一个沿X轴旋转的自定义补间动画,其方法如下:
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
// TODO Auto-generated method stub
//camera保存初始状态
camera.save();
//绕X轴旋转
camera.rotateX(1000 * interpolatedTime);
//从Transformation获得Matrix
Matrix matrix = t.getMatrix();
//将变换应用到matrix上
camera.getMatrix(matrix);
//camera恢复初始状态
camera.restore();
}
若要在API11之前的版本使用属性动画,可以调用Nine Old Androids开源库,使用方法与官方API一样,只是导入的包不同。
增强版补间动画,几乎可以定义任何属性变化,以及对任何对象执行动画(不管是否显示在屏幕上),属性动画需要定义的属性有:
要使用属性动画还需使用一个Evaluator,该工具类控制属性动画如何计算属性值。Android提供了如下Evaluator:
为ValueAnimator注册AnimatorUpdateListener监听器,在该监听器中可以监听ValueAnimator计算出来的值的改变,并将这些值应用到指定对象
ValueAnimator animator = ValueAnimator.ofFloat(0.1f, 1f);
animator.setDuration(3000);
animator.start();
上面的例子只是计算了在3000毫秒里float的值从0.1到1的变化的值,并没有把这些计算的值应用到任何对象上,因此也不会显示任何动画。
除此之外,还可以提供一个自定义的Evaluator计算器,例如:
ValueAnimator anim = ValueAnimator.ofObject(new MyTypeEvaluator(), startVal, endVal);
如果希望使用ValueAnimator创建动画,还需要注册一个监听器:AnimatorUpdateListener,该监听器负责更新对象的属性值,实现这个监听的时候,可以通过getAnimatiedValue()的方法来获取当前帧的值,并将该计算出来的值应用到指定对象上。
ObjectAnimator继承了ValueAnimator,ObjectAnimatior在创建时需要指定对象和对象属性, 因此不需要注册AnimatorUpdateListener。
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, “alpha”, 0f, 1f);
注意事项:
具体例子如下:
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//过滤触摸事件,只对按下和移动事件进行响应
if(event.getAction() != MotionEvent.ACTION_DOWN &&
event.getAction() != MotionEvent.ACTION_MOVE) {
return false;
}
BitmapHolder newBmp = addBmp(event.getX(), event.getY());
float startY = newBmp.getY();
float endY = getHeight() - 15f;
float h = (float)getHeight();
float eventY = event.getY();
int duration = (int)(500 * ((h - eventY) / h));
//掉落动画
ObjectAnimator fallAnimation = ObjectAnimator.ofFloat(newBmp, "y", startY, endY);
fallAnimation.setDuration(duration);
fallAnimation.setInterpolator(new AccelerateInterpolator());
//重复次数为1,重复模式为恢复模式,使得图片落下后回弹
fallAnimation.setRepeatCount(1);
fallAnimation.setRepeatMode(ValueAnimator.REVERSE);
//旋转动画
ObjectAnimator rotateAnimation = ObjectAnimator.ofFloat(newBmp, "rotate", 8000, 0);
rotateAnimation.setDuration(duration);
rotateAnimation.setInterpolator(new AccelerateInterpolator());
rotateAnimation.setRepeatCount(1);
rotateAnimation.setRepeatMode(ValueAnimator.REVERSE);
//缩放动画
ObjectAnimator scaleAnimation = ObjectAnimator.ofFloat(newBmp, "scale", 1, 4);
scaleAnimation.setDuration(duration);
scaleAnimation.setInterpolator(new AccelerateInterpolator());
scaleAnimation.setRepeatCount(1);
scaleAnimation.setRepeatMode(ValueAnimator.REVERSE);
//消失动画
ObjectAnimator fadeAnimation = ObjectAnimator.ofInt(newBmp, "a", 255, 0);
fadeAnimation.setDuration(500);
fadeAnimation.setInterpolator(new AccelerateInterpolator());
//动画集,设置动画为同时播放
AnimatorSet animSet = new AnimatorSet();
animSet.play(fallAnimation).with(rotateAnimation);
animSet.play(rotateAnimation).with(scaleAnimation);
//监控动画状态,动画完结后移除图片
fadeAnimation.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
bmps.remove(((ObjectAnimator)animation).getTarget());
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
//先播放图片动画,完成后播放消失动画
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(fadeAnimation).after(animSet);
animatorSet.start();
return true;
}
属性动画效果: