Android的动画可以分为三种,View动画、帧动画、属性动画。View动画通过对场景里的对象不断做图像变化(平移、缩放、旋转、透明度)从而产生动画效果,它是一种渐进式动画,而且View动画支持自定义。帧动画可以理解为图片切换动画(如果图片过多,会导致OOM)。属性动画为API11的新特性,属性动画通过通过动态地改变对象的属性从而达到动画效果。

  • View动画

View动画的种类:View动画的四种变换效果对应着Animation的四个子类。TranslateAnimation,ScaleAnimation,RotateAnimation,AlphaAnimation。这四种动画可以通过XML来定义,也可以通过代码动态创建。对于View动画来说,建议XML来定义,这是因为XML格式的动画可读性好。

View动画的四种变换
名称 标签 子类 效果
平移动画 <translate> TranslateAnimation 移动View
缩放动画 <scale> ScaleAnimation 放大或缩小View
旋转动画 <rotate> RotateAnimation 旋转View
透明度动画 <alpha> AlphaAnimation 改变View的透明度
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:shareInterpolator="true"
android:duration="1000"
android:fillAfter="false"> <alpha android:fromAlpha="float"
android:toAlpha="float" />
<scale android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" /> <translate android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
</set>

View动画可以是单个动画,也可以是一系列动画组成。<set>表示动画集合,对应AnimationSet类。

android:interpolator:表示动画集合所使用的插值器,插值器影响动画的速度,比如非匀速动画就需要通过插值器来控制动画的播放速度。

android:shareInterpolator:表示集合中的动画是否共享同一个插值器。如果不指定插值器,那么子动画就需要单独指定所需要的插值器或者使用默认值。

AlphaAnimation anim = (AlphaAnimation) AnimationUtils.loadAnimation(this, R.anim.anim_test);
TextView tv = findViewById(R.id.tv);
tv.startAnimation(anim);

除了XML定义动画之外,还可以使用代码创建动画。

AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(300);
TextView tv = findViewById(R.id.tv);
tv.startAnimation(alphaAnimation);

注意:通过Animation的setAnimationListener的方法可以给View动画添加过程监听。如适用于带动画的启动页,监听动画完成后进入MainActivity。

anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
});

自定义View动画:

自定义View动画是一件简单而复杂的事情。说简单是:因为派生一种新动画只需要集成Animation这个抽象类,然后重写它的initialize和applyTransformation方法。在initialize中进行初始化工作,在applyTransformation中进行相应的矩阵变换即可。很多时候需要Camera来简化矩阵变换过程。说复杂,是因为需要运用到矩阵变换的过程,使用到数学上的概念。之后再做相关的分析讲解。

  • 帧动画

帧动画顺序播放一组预先定义好的图片,类似电影播放。不同于View动画,系统提供另外一个类AnimationDrawable来使用帧动画。帧动画的使用比较简单,先使用XML来定义一个AnimationDrawable。在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/img1" android:duration="500"/>
<item android:drawable="@drawable/img2" android:duration="500"/>
<item android:drawable="@drawable/img3" android:duration="500"/>
</animation-list>

将上述的Drawable作为View的背景并通过Drawable来播放动画。

TextView tv = findViewById(R.id.tv);
tv.startAnimation(alphaAnimation);
AnimationDrawable animationDrawable = (AnimationDrawable) tv.getBackground();
animationDrawable.start();

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

  • View动画的特殊场景使用

在一些特殊场景下,如ViewGroup中控制子元素的出场效果,在Activity中实现不同Activity之间的切换效果。

LayoutAnimation作用于ViewGroup,作为ViewGroup指定一个动画,这样当它的子元素出场时都具有这样的效果。常见的ListView的Item的出场以一定的动画效果出现。

定义LayoutAnimation如下:

//res/anim/anim_layout.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" />

delay表示子元素开始动画的时间延迟。比如说元素入场动画周期为300ms,那么0.5表示每个子元素都需要延迟150ms才能播放入场动画。第一个子元素延迟150ms开始播放入场动画,第二个子元素延迟300m开始播放入场,以此类推。

animationOrder:子元素动画顺序,normal, reverse和random。

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

为ViewGroup指定android:layoutAnimation属性,对于ListView而言,指定之后就是Item的出场动画了。除了XML中指定LayoutAnimation之外,还可以通过LayoutAnimationController来实现,具体如下:

ListView listView = findViewById(R.id.list_view);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);

Activity的切换效果:

Activity有默认的切换效果,但是这个效果是可以自定义的,主要用到overridePendingTransition(int enterAnim, int exitAnim)这个方法,这个必须在startActivity(intent)和finish()之后被调用才能生效,它的参数含义如下:

enterAnim - Activity被打开时,所需要的动画资源id

exitAnim - Activity被暂停时,所需要的动画资源id

当启动一个Activity时,可以按照如下方式为其添加自定义的切换效果:

Intent intent = new Intent(this, TestActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.enter_anim, R.anim.exitAnim);

当Activityt退出时,也可以为其指定自定义的切换效果:

@Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.enter_anim, R.anim.exitAnim);
}

Fragment也可以添加切换效果,可以通过FragmentTransaction中的setCustomAnimations()方法来添加切换动画,这个切换动画需要时View动画。还有其他的方法为Activity和Fragment添加切换动画,但是需要考略兼容为题。

  • 属性动画

属性动画是API11新加入的特性,和View动画不同,它对作用的对象进行扩展,属性动画可以对任何对象做动画,甚至还可以没有对象。属性动画可以对任意对象的属性进行动画而不仅仅是View。属性动画中有ValueAnimator, ObjectAnimator和AnimatorSet等概念。为兼容之前的版本,采用nineoldandroids源动画库。

ObjectAnimator继承自ValueAnimator,AnimatorSet是动画集合。属性动画需要定义在res/animator/目录下。

  1. 改变一个对象myObject的translationY属性,让其沿着Y轴向上移动一段距离,在默认的时间完成。
    1. ObjectAnimator.ofFloat(tv, "translationY", -myObject.getHeight())
      .start();
  2. 改变一个对象背景色属性,典型的改变View背景,下面的动画可以让背景色在3s内实现从0xFFFF8080到0xFF8080FF的渐变,动画会无限循环而且会有反转的效果。
    1. ValueAnimator colorAnim = ObjectAnimator.ofInt(myObject, "backgroundColor", 0xFFFF8080, 0xFF8080FF);
      colorAnim.setDuration(3000);
      colorAnim.setEvaluator(new ArgbEvaluator());
      colorAnim.setRepeatCount(ValueAnimator.INFINITE);
      colorAnim.setRepeatMode(ValueAnimator.REVERSE);
      colorAnim.start();
  3. 动画集合,5秒内对View的旋转,平移,缩放和透明度都进行改变。
    1. AnimatorSet set = new AnimatorSet();
      set.playTogether(
      ObjectAnimator.ofFloat(view, "rotationX", 0, 360),
      ObjectAnimator.ofFloat(view, "rotationY", 0, 180),
      ObjectAnimator.ofFloat(view, "rotation", 0, -90),
      ObjectAnimator.ofFloat(view, "translationX", 0, 100),
      ObjectAnimator.ofFloat(view, "translationY", 0, 100),
      ObjectAnimator.ofFloat(view, "scaleX", 1, 1.5f),
      ObjectAnimator.ofFloat(view, "scaleY", 1, 0.5f),
      ObjectAnimator.ofFloat(view, "alpha", 1, 0.5f, 1)
      );
      set.setDuration(5 * 1000).start();

属性动画除了代码实现之外,还可以通过XML来定义。

eg.

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator android:propertyName="x"
android:duration="300"
android:valueTo="300"
android:valueType="intType" /> <objectAnimator android:propertyName="y"
android:duration="300"
android:valueTo="300"
android:valueType="intType"/>
</set>

加载上面的属性动画:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.property_animator);
set.setTarget(view);
set.start();

建议:属性动画采用代码来实现,这是因为代码的方式会比较简单,更重要的是,在一个属性起始值无法确定的情况下,将无法将属性定义在xml文件中。

  • 插值器和估值器

 TimeInterpolater:时间插值器,它的作用是根据时间流逝的百分比来计算出当前属性改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速动画)、AccelerateDecelerateInterpolator(加速减速插值器:动画两头慢,中间快),DeceleratrInterpolator(减速插值器:动画越来越慢)等。

TypeEvaluator:类型估值算法,也叫做估值器。它的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预置的有IntEvaluator(针对整型属性),FloatEvaluator(针对浮点型属性),ArgbEvaluator(针对Color属性)。

线性差值器,属于匀速动画,其源码为:

/**
* An interpolator where the rate of change is constant
*/
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public LinearInterpolator() {
} public LinearInterpolator(Context context, AttributeSet attrs) {
} public float getInterpolation(float input) {
return input; /** 输入值和返回值一样 */
} /** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}

那到底输入数值是什么?这需要估值算法来确定,如整型估值器的源码为:

public class IntEvaluator implements TypeEvaluator<Integer> {

    /**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start value; should be of type <code>int</code> or
* <code>Integer</code>
* @param endValue The end value; should be of type <code>int</code> or <code>Integer</code>
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}

evaluate方法的三个参数分别是估值小数,起始值,结束值。例子:匀速动画,对象从0位置到100,当估值小数位0.5的时候,根据算法result = 0 + 0.5(100 - 0) = 50。

属性动画要求对象有该属性的set方法和get方法(可选)。除了系统预置的插值器和估值算法外,我们还可以自定义。自定义差值算法需要实现Interpolator或TimeInterpolator;自定义估值算法需要实现TypeEvaluator。

属性动画的监听:

有两个常用的属性动画监听:AnimatorListener, AnimatorUpdateListener

ObjectAnimator animator = new ObjectAnimator();
animator.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) {}
});

从AnimatorListener的定义来看,它可以监听动画的开始,结束,取消和重复动画。

public static interface AnimatorUpdateListener {
/**
* <p>Notifies the occurrence of another frame of the animation.</p>
*
* @param animation The animation which was repeated.
*/
void onAnimationUpdate(ValueAnimator animation); }

AnimatorUpdateListener比较特殊,它会监听整个动画过程,动画是由许多帧组成的,每播放一帧onAnimationUpdate()就会被调用一次,利用这个特征,我们可以做一些特殊事情。

  • 对任意属性做动画

例如TextView的宽度动画变为800的动画,当layout_width的属性为wrap_content时,是有动画的,但是如果设置为固定值之后,下面的属性动画就没有效果了。

//高度从原来的默认值变为800
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(textView, "width", 800);
objectAnimator.setDuration(500);
objectAnimator.start();

这是因为:

public void setWidth(int pixels) {
mMaxWidth = mMinWidth = pixels;
mMaxWidthMode = mMinWidthMode = PIXELS; requestLayout();
invalidate();
}
 public final int getWidth() {
return mRight - mLeft;
}

setWidth不是所谓意义上的宽度设置,所以就不会产生动画。对任意属性做动画,一般需要有set和get方法,设置流程如下:

如果没有属性设置获取权限,可以定义一个包裹类进行封装,实现set和get方法;如:

public static class ViewWrapper{

        private View mTarget;

        public ViewWrapper(View target){
mTarget = target;
} public void setWidth(int width){
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
} public int getWidth(){
return mTarget.getLayoutParams().width;
}
}
ViewWrapper viewWrapper = new ViewWrapper(view);
ObjectAnimator widthAnimator = ObjectAnimator.ofInt(viewWrapper, "width", btn.getWidth(), 800)
.setDuration(500);
widthAnimator.start();

这样,上面的TextView就可以实现宽度的动画效果了。

自定义View设置相关属性,进行动画案例:

/**
* 自定义圆环
* 对属性progress设置set和get方法
* 就可以对CircleProgress的progress进行属性动画
*/
public class CircleProgress extends View{ private Paint mPaint;
private RectF rectF;
private int progress = 270;
int width, height; public CircleProgress(Context context) {
super(context);
init();
} public CircleProgress(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
} public CircleProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void init(){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(20);
mPaint.setColor(Color.RED);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY){
width = widthSize;
}else{
width = 100; //设置为默认值
} if (heightMode == MeasureSpec.EXACTLY){
height = heightSize;
}else{
height = 100; //设置为默认值
}
rectF = new RectF(20, 20, width-20, height-20);
setMeasuredDimension(Math.min(width, height), Math.min(width, height)); //矩形
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(rectF, -90, progress, false, mPaint);
invalidate();
} public void setProgress(int progress){
this.progress = progress;
} public int getProgress(){
return progress;
}
}

Android之动画的更多相关文章

  1. Android属性动画

    这几天看郭神的博客 Android属性动画完全解析(上),初识属性动画的基本用法之后,我自己突然想实现一种动画功能,就是我们在携程网.阿里旅行等等手机APP端买火车票的时候,看到有选择城市,那么就有出 ...

  2. android 自定义动画

    android自定义动画注意是继承Animation,重写里面的initialize和applyTransformation,在initialize方法做一些初始化的工作,在applyTransfor ...

  3. 【转】android 属性动画之 ObjectAnimator

    原文网址:http://blog.csdn.net/feiduclear_up/article/details/39255083 前面一篇博客讲解了 android 简单动画之 animtion,这里 ...

  4. Android属性动画之ValueAnimation

    ValueAnimation是ObjectAnimation类的父类,经过前几天的介绍,相信大家对ObjectAnimation有了 一定的认识,今天就为大家最后介绍一下ValueAnimation, ...

  5. Android属性动画之ObjectAnimator

    相信对于Android初学者,对于Android中的动画效果一定很感兴趣,今天为大家总结一下刚刚学到的属性动画案例. 首先和一般的Android应用一样,我们先建一个工程,为了方便,我们的布局文件中就 ...

  6. 79.Android之动画基础

    转载:http://a.codekk.com/detail/Android/lightSky/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8 ...

  7. Android属性动画完全解析(下)

    转载:http://blog.csdn.net/guolin_blog/article/details/44171115 大家好,欢迎继续回到Android属性动画完全解析.在上一篇文章当中我们学习了 ...

  8. Android属性动画完全解析(上),初识属性动画的基本用法

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43536355 在手机上去实现一些动画效果算是件比较炫酷的事情,因此Android系 ...

  9. Android属性动画完全解析(中)

    转载:http://blog.csdn.net/guolin_blog/article/details/43536355 大家好,在上一篇文章当中,我们学习了Android属性动画的基本用法,当然也是 ...

  10. Android属性动画完全解析(上)

    Android属性动画完全解析(上) 转载:http://blog.csdn.net/guolin_blog/article/details/43536355 在手机上去实现一些动画效果算是件比较炫酷 ...

随机推荐

  1. Dynamics CRM 电子邮件服务器配置文件Advanced配置中关闭SSL

    在新建电子邮件服务器配置文件时Advanced中的Use SSL for Incoming/Outgoing Connection默认都是启用的而且无法编辑,启用SSL当然是为了安全的考虑,但当客户的 ...

  2. Android的自动完成文本框-android学习之旅(二十六)

    AutoComplicatedTextView简介 AutoComplicatedTextView是从EditText派生出来的,可以使用EditText的所有的属性.当用户输入一定的内容后,会有提示 ...

  3. String压缩 解压缩

    数据传输时,有时需要将数据压缩和解压缩,本例使用GZIPOutputStream/GZIPInputStream实现. 1.使用ISO-8859-1作为中介编码,可以保证准确还原数据 2.字符编码确定 ...

  4. 【MATLAB】用MATLAB绘制奥运五环

    [MATLAB]用MATLAB绘制奥运五环 今天用MATLAB绘制了一个奥运五环,好吧,实际上是帮人做作业,嘿嘿. 贴代码: clear; clc; N = 1000; angle = linspac ...

  5. Uva - 512 - Spreadsheet Tracking

    Data in spreadsheets are stored in cells, which are organized in rows (r) and columns (c). Some oper ...

  6. svn 集成 redmine 账户验证的终极解决方案

    svn 集成 redmine 账户验证的终极解决方案 赖勇浩(http://laiyonghao.com) 动机 对于大部分开发团队来说,一般都需要一套 SCM 系统,通常是 svn + redmin ...

  7. UNIX网络编程——经常使用的套接字选项

    1.设置/获取套接字选项 int setsockopt(int socket, int level, int option_name, const void *option_value, sockle ...

  8. (NO.00004)iOS实现打砖块游戏(三):游戏主场景和砖块

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 制作墙体 首先在SpriteBuilder中新建Wall.ccb ...

  9. [Redmine] Centos5上安装Redmine3.0+nginx+thin部署

    项目管理的需要所以安装Redmine,其实wiki放在上面也不错的. 首先是安装,ruby应用第一次装,把坑记住. nginx, mysql是已经安装好的,只需要配置, 结合nginx的部署方式很多, ...

  10. CUDA程序的调试总结【不定时更新】

    1 )CUDA的程序,经常犯,但是很难发现的一个错误就是同步问题. 描述下实例 for (k = 0; k < N; k+=BS) { sda[tx] = gda[tx+index]; __sy ...