Android动画详解:

Android动画详解:

Animation动画的种类:

  • Android系统提供了很多丰富的API去实现UI的2D与3D动画,最主要的划分可以分为如下几类:
    • View Animation: 视图动画在古老的Android版本系统中就已经提供了,只能被用来设置View的动画。
      注意: 补间动画执行之后并未改变View的真实布局属性值。切记这一点,譬如我们在Activity中有一个Button在屏幕上方,我们设置了平移动画移动到屏幕下方然后保持动画最后执行状态呆在屏幕下方,这时如果点击屏幕下方动画执行之后的Button是没有任何反应的,而点击原来屏幕上方没有Button的地方却响应的是点击Button的事件。
    • Drawable Animation: 这种动画(也叫Frame动画、帧动画)其实可以划分到视图动画的类别,专门用来一个一个的显示Drawable的resources,就像放幻灯片一样。
      注意: google文档中建议不要在oncreate()方法中调用start(),这是因为AnimationDrawable可能还没有attach到window上,最好的调运时机是onWindowFocusChanged()方法中。
    • Property Animation: 属性动画只对Android 3.0(API 11)以上版本的Android系统才有效,这种动画可以设置给任何Object,包括那些还没有渲染到屏幕上的对象。这种动画是可扩展的,可以让你自定义任何类型和属性的动画。
      注意:弥补了View动画的缺陷,你可以为一个对象的任意属性添加动画,对象自己的属性会被真的改变;当对象的属性变化的时候,属性动画会自动刷新屏幕;属性动画改变的是对象的真实属性,而且属性动画不止用于View,还可以用于任何对象。
      1. 1.

帧动画:

  • 根据Api文档使用步骤为:
    • 在res/drawable下构建xml文件,onshot为true为播发一次,false为循环播发
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="true">
                <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
                <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
                <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
            </animation-list>
* 在代码中触发:
@Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);

                mImageView = (ImageView) findViewById(R.id.img_drawable);
                //版本控制,Api14后关闭硬件加速.
                if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.ICE_CREAM_SANDWICH){
                    mImageView.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
                }
                mImageView.setBackgroundResource(R.drawable.drawable_animation);
                girl = (AnimationDrawable) mImageView.getBackground();
            }

            @Override
            public boolean onTouchEvent(MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        girl.start();
                        return true;
                }
                return super.onTouchEvent(event);
            }
  • 使用过程中注意问题:
    • 出现Cannot generate texture from bitmap异常,主要原因是由于4.0之后系统开启了GPU硬件加速导致的,因此,我们可以在图片加载之前,设置ImageView为关闭硬件加速状态,之所以要加上版本控制,是因为设置图片的非硬件加速模式是在api11之后添加的,因此,我们需要进行版本的控制,否则,在低版本上运行会报错。
    • 使用帧动画避免不了要使用图片,AS中不支持gif格式图片的直接使用,最好使用png格式.

补间动画

  • 属性讲解:

    • Animation属性:
    xml属性java方法解释
    android:detachWallpapersetDetachWallpaper(boolean)是否在壁纸上运行
    android:durationsetDuration(long)动画持续时间,毫秒为单位
    android:fillAftersetFillAfter(boolean)控件动画结束时是否保持动画最后的状态
    android:fillBeforesetFillBefore(boolean)控件动画结束时是否还原到开始动画前的状态
    android:fillEnabledsetFillEnabled(boolean)与android:fillBefore效果相同
    android:interpolatorsetInterpolator(Interpolator)设定插值器(指定的动画效果,譬如回弹等)
    android:repeatCountsetRepeatCount(int)重复次数
    android:repeatModesetRepeatMode(int)重复类型有两个值,reverse表示倒序回放,restart表示从头播放
    android:startOffsetsetStartOffset(long)调用start函数之后等待开始运行的时间,单位为毫秒
    android:zAdjustmentsetZAdjustment(int)表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal
    • Alpha属性详解
    xml属性java方法解释
    android:fromAlphaAlphaAnimation(float fromAlpha, …)动画开始的透明度(0.0到1.0,0.0是全透明,1.0是不透明)
    android:toAlphaAlphaAnimation(…, float toAlpha)动画结束的透明度,同上

    * Rotate属性详解

    xml属性java方法解释
    android:fromDegreesRotateAnimation(float fromDegrees, …)旋转开始角度,正代表顺时针度数,负代表逆时针度数
    android:toDegreesRotateAnimation(…, float toDegrees, …)旋转结束角度,正代表顺时针度数,负代表逆时针度数
    android:pivotXRotateAnimation(…, float pivotX, …)缩放起点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)
    • scale属性详解
    xml属性java方法解释
    android:fromXScaleScaleAnimation(float fromX, …)初始X轴缩放比例,1.0表示无变化
    android:toXScaleScaleAnimation(…, float toX, …)结束X轴缩放比例
    android:fromYScaleScaleAnimation(…, float fromY, …)初始Y轴缩放比例
    android:toYScaleScaleAnimation(…, float toY, …)结束Y轴缩放比例
    android:pivotXScaleAnimation(…, float pivotX, …)缩放起点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)
    android:pivotYScaleAnimation(…, float pivotY)缩放起点Y轴坐标,同上规律

    * Translate属性详解

    xml属性java方法解释
    android:fromXDeltaTranslateAnimation(float fromXDelta, …)起始点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)
    android:fromYDeltaTranslateAnimation(…, float fromYDelta, …)起始点Y轴从标,同上规律
    android:toXDeltaTranslateAnimation(…, float toXDelta, …)结束点X轴坐标,同上规律
    android:toYDeltaTranslateAnimation(…, float toYDelta)结束点Y轴坐标,同上规律
    android:pivotYRotateAnimation(…, float pivotY)缩放起点Y坐标,同上规律
  • 具体使用:

    • 放缩:
      • res/anim/xml配置文件实现动画
                <scale xmlns:android="http://schemas.android.com/apk/res/android"
                    android:duration="2000"
                    android:fromXScale="0.0"
                    android:fromYScale="0.0"
                    android:pivotX="50%"
                    android:pivotY="50%"
                    android:repeatCount="2"
                    android:repeatMode="reverse"
                    android:toXScale="2.0"
                    android:toYScale="2.0" >
                </scale>
                Animation sa = AnimationUtils.loadAnimation(this, R.anim.scale);
                iv.startAnimation(sa);
    * 代码方式实现:
 ScaleAnimation sa = new ScaleAnimation(0.0f, 2.0f, 0.0f,2.0f,
                        Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);
                sa.setDuration(2000);
                sa.setRepeatCount(2);
                sa.setRepeatMode(Animation.REVERSE);
                iv.startAnimation(sa);
* 位移:
    *  res/anim/xml配置文件实现动画
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
                    android:duration="2000"
                    android:fromXDelta="-50%p"
                    android:fromYDelta="-50%p"
                    android:repeatCount="2"
                    android:repeatMode="reverse"
                    android:toXDelta="50%p"
                    android:fillAfter="true"
                    android:toYDelta="50%p" >
                </translate>

                Animation ta = AnimationUtils.loadAnimation(this, R.anim.trans);
                iv.startAnimation(ta);
    * 代码实现:
TranslateAnimation animation = new TranslateAnimation(0, 0, 0, 250);
                animation.setDuration(2000);// 设置动画的时长
                animation.setFillAfter(true);// 停在结果位置
                iv.startAnimation(animation);
* 旋转:
    * res/anim/xml配置文件实现动画
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
                    android:fromDegrees="0"
                    android:toDegrees="360"
                    android:duration="2000"
                    android:repeatCount="2"
                    android:repeatMode="reverse"
                    android:pivotX="50%p"
                    android:pivotY="50%p" >
                </rotate>

                Animation ra = AnimationUtils.loadAnimation(this, R.anim.rotate);
                iv.startAnimation(ra);
    * 代码实现:
 RotateAnimation ra = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF,
                                        0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                ra.setDuration(2000);
                ra.setRepeatCount(2);
                ra.setRepeatMode(Animation.REVERSE);
                iv.startAnimation(ra);
* 透明:
    * res/anim/xml配置文件实现:
 <alpha xmlns:android="http://schemas.android.com/apk/res/android"
                    android:fromAlpha="0"
                    android:toAlpha="1.0"
                    android:duration="2000"
                    android:repeatCount="2"
                    android:repeatMode="reverse" >
                </alpha>

                Animation aa = AnimationUtils.loadAnimation(this, R.anim.alpha);
                iv.startAnimation(aa);
    * 代码实现:
    AlphaAnimation aa = new AlphaAnimation(0.0f, 1.0f);
                // 动画播放2秒
                aa.setDuration(2000);
                aa.setRepeatCount(2);
                aa.setRepeatMode(Animation.REVERSE);
                iv.startAnimation(aa);
* 动画集:
    * res/anim/xml配置文件实现:<set android:shareInterpolator="false">
    <scale
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromXScale="1.0"
        android:toXScale="1.4"
        android:fromYScale="1.0"
        android:toYScale="0.6"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="false"
        android:duration="700" />
    <set android:interpolator="@android:anim/decelerate_interpolator">
        <scale
           android:fromXScale="1.4"
           android:toXScale="0.0"
           android:fromYScale="0.6"
           android:toYScale="0.0"
           android:pivotX="50%"
           android:pivotY="50%"
           android:startOffset="700"
           android:duration="400"
           android:fillBefore="false" />
        <rotate
           android:fromDegrees="0"
           android:toDegrees="-45"
           android:toYScale="0.0"
           android:pivotX="50%"
           android:pivotY="50%"
           android:startOffset="700"
           android:duration="400" />
    </set>
</set>
    ImageView image = (ImageView) findViewById(R.id.image);
    Animation hyperspaceJump = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);

* 代码实现:

AnimationSet set = new AnimationSet(false);
                TranslateAnimation ta = new TranslateAnimation(
                        Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 0.5f,
                        Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                ta.setDuration(2000);
                ta.setRepeatCount(2);
                ta.setRepeatMode(Animation.REVERSE);
                RotateAnimation ra = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF,
                        0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                ra.setDuration(2000);
                ra.setRepeatCount(2);
                ra.setRepeatMode(Animation.REVERSE);
                ScaleAnimation sa = new ScaleAnimation(0.0f, 2.0f, 0.0f, 2.0f,
                        Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                        0.5f);
                sa.setDuration(2000);
                sa.setRepeatCount(2);
                sa.setRepeatMode(Animation.REVERSE);
                set.addAnimation(sa);
                set.addAnimation(ta);
                set.addAnimation(ra);
                iv.startAnimation(set);
    > 注意:默认情况下,动画集所有动画都是同时执行,但是可以设置startoffset属性配置延时执行动画.

属性动画:

  • 属性动画继承关系图:

    这里写图片描述

    java类名xml关键字描述信息
    ValueAnimator 放置在res/animator/目录下在一个特定的时间里执行一个动画
    TimeAnimator不支持时序监听回调工具
    ObjectAnimator 放置在res/animator/目录下一个对象的一个属性动画
    AnimatorSet 放置在res/animator/目录下动画集合
  • ObjectAnimation:

    • 继承自ValueAnimator,允许你指定要进行动画的对象以及该对象的一个属性。该类会根据计算得到的新值自动更新属性。大多数的情况使用ObjectAnimator就足够了,因为它使得目标对象动画值的处理过程变得足够简单,不用像ValueAnimator那样自己写动画更新的逻辑,但是ObjectAnimator有一定的限制,比如它需要目标对象的属性提供指定的处理方法(譬如提供getXXX,setXXX方法),这时候你就需要根据自己的需求在ObjectAnimator和ValueAnimator中看哪种实现更方便了。

    • ObjectAnimator类提供了ofInt、ofFloat、ofObject这个三个常用的方法,这些方法都是设置动画作用的元素、属性、开始、结束等任意属性值。当属性值(上面方法的参数)只设置一个时就把通过getXXX反射获取的值作为起点,设置的值作为终点;如果设置两个(参数),那么一个是开始、另一个是结束。

      特别注意:ObjectAnimator的动画原理是不停的调用setXXX方法更新属性值,所有使用ObjectAnimator更新属性时的前提是Object必须声明有getXXX和setXXX方法。

    • 我们通常使用ObjectAnimator设置View已知的属性来生成动画,而一般View已知属性变化时都会主动触发重绘图操作,所以动画会自动实现;但是也有特殊情况,譬如作用Object不是View,或者作用的属性没有触发重绘,或者我们在重绘时需要做自己的操作,那都可以通过如下方法手动设置:

      ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0,  1).setDuration(2000);
      mObjectAnimator.addUpdateListener(new AnimatorUpdateListener()
              {
                  @Override
                  public void onAnimationUpdate(ValueAnimator animation)
                  {
                      //int value = animation.getAnimatedValue();  可以获取当前属性值
                      //view.postInvalidate();  可以主动刷新
                      //view.setXXX(value);
                      //view.setXXX(value);
                      //......可以批量修改属性
                  }
              });
      
    • ObjectAnimator属性解释:

      xml属性解释
      android:propertyNameString类型,必须要设置的节点属性,代表要执行动画的属性(通过名字引用),辟如你可以指定了一个View的”alpha” 或者 “backgroundColor” ,这个objectAnimator元素没有对外说明target属性,所以你不能在XML中设置执行这个动画,必须通过调用loadAnimator()方法加载你的XML动画资源,然后调用setTarget()应用到具备这个属性的目标对象上(譬如TextView)。
      android:valueTofloat、int或者color类型,必须要设置的节点属性,表明动画结束的点;如果是颜色的话,由6位十六进制的数字表示。
      android:valueFrom相对应valueTo,动画的起始点,如果没有指定,系统会通过属性的get方法获取,颜色也是6位十六进制的数字表示。
      android:duration动画的时长,int类型,以毫秒为单位,默认为300毫秒。
      android:startOffset动画延迟的时间,从调用start方法后开始计算,int型,毫秒为单位。
      android:repeatCount一个动画的重复次数,int型,”-1“表示无限循环,”1“表示动画在第一次执行完成后重复执行一次,也就是两次,默认为0,不重复执行。
      android:repeatMode重复模式:int型,当一个动画执行完的时候应该如何处理。该值必须是正数或者是-1,“reverse”会使得按照动画向相反的方向执行,可实现类似钟摆效果。“repeat”会使得动画每次都从头开始循环。
      android:valueType关键参数,如果该value是一个颜色,那么就不需要指定,因为动画框架会自动的处理颜色值。有intType和floatType(默认)两种:分别说明动画值为int和float型。
    • 一般情况下ObjectAnimator使用方式:

      • res/anim/xml配置文件实现:

         <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
            android:duration="3000"
            android:propertyName="translationX"
            android:valueFrom="0"
            android:valueTo="300"
            android:valueType="floatType" >
        </objectAnimator>
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.trans);  
        animator.setTarget(v);
        animator.start();
        
      • 代码中实现:

        ObjectAnimator animator = ObjectAnimator.ofFloat(iv, "translationY", 0,250, 100, 200, 250);     
        animator.setDuration(5000);
        animator.start();
        
  • ValueAnimator:

    • 属性动画中的时间驱动,管理着动画时间的开始、结束属性值,相应时间属性值计算方法等。包含所有计算动画值的核心函数以及每一个动画时间节点上的信息、一个动画是否重复、是否监听更新事件等,并且还可以设置自定义的计算类型。

      特别注意:ValueAnimator只是动画计算管理驱动,设置了作用目标,但没有设置属性,需要通过updateListener里设置属性才会生效。

      ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight);  //定义动画
      animator.setTarget(view);   //设置作用目标
      animator.setDuration(5000).start();
      animator.addUpdateListener(new AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator animation){
              float value = (float) animation.getAnimatedValue();
              view.setXXX(value);  //必须通过这里设置属性值才有效
              view.mXXX = value;  //不需要setXXX属性方法
          }
      });
      

      看上去好像和ObjectAnimator没什么区别,实际上正是由于ValueAnimator不直接操作属性值,所以要操作对象的属性可以不需要setXXX与getXXX方法,你完全可以通过当前动画的计算去修改任何属性。

    • 实际例子:

      mEvaluator= findViewById(R.id.view);
      mEvaluator.setBackgroundColor(Color.RED);
      ValueAnimator animator= ValueAnimator.ofInt(50,100);
      animator.setDuration(2000);
      animator.start();
      animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator animation) {
              int value = (int) animation.getAnimatedValue();
              ViewGroup.LayoutParams params = mEvaluator.getLayoutParams();
              params.width=value;
              mEvaluator.setLayoutParams(params);
          }
      });
      
  • Evaluators

    • Evaluators就是属性动画系统如何去计算一个属性值。它们通过Animator提供的动画的起始和结束值去计算一个动画的属性值。
    • 系统已实现的类为:

      • IntEvaluator:整数属性值。
      • FloatEvaluator:浮点数属性值。
      • ArgbEvaluator:十六进制color属性值。
      • TypeEvaluator:用户自定义属性值接口,譬如对象属性值类型不是int、float、color类型,你必须实现这个接口去定义自己的数据类型。
    • 使用ArgbEvalutor构建呼吸灯动画:

      mEvaluator= findViewById(R.id.view);
      ObjectAnimator animator = ObjectAnimator.ofObject(mEvaluator, "backgroundColor", 
                      new ArgbEvaluator(), Color.BLACK, Color.BLUE, Color.RED);
      animator.setDuration(2000);
      animator.setRepeatCount(ObjectAnimator.INFINITE);
      animator.setRepeatMode(ObjectAnimator.REVERSE);
      animator.start();
      

      使用ObjectAnimator是因为做动画的View,其有setBackground(int color)方法,虽然该参数类型为Int,但是不能使用ofInt().

    • 使用自定义Evalutor来构建动画:
            ValueAnimator valueAnimator = new ValueAnimator();
            valueAnimator.setDuration(5000);
            valueAnimator.setObjectValues(new float[2]); //设置属性值类型
            valueAnimator.setInterpolator(new LinearInterpolator());
            valueAnimator.setEvaluator(new TypeEvaluator<float[]>()
            {
                @Override
                public float[] evaluate(float fraction, float[] startValue,
                                        float[] endValue)
                {
                    //实现自定义规则计算的float[]类型的属性值
                    float[] temp = new float[2];
                    temp[0] = fraction * 2;
                    temp[1] = (float)Math.random() * 10 * fraction;
                    return temp;
                }
            });

            valueAnimator.start();
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
            {
                @Override
                public void onAnimationUpdate(ValueAnimator animation)
                {
                    float[] xyPos = (float[]) animation.getAnimatedValue();
                    view.setHeight(xyPos[0]);   //通过属性值设置View属性动画
                    view.setWidth(xyPos[1]);    //通过属性值设置View属性动画
                }
            });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值