Android 动画详解「建议收藏」

Android 动画详解「建议收藏」动画的分类Android动画可以分别为三种,View动画,帧动画,属性动画。其实帧动画也属于View动画的一种,只不过他的表现形式不同而已,View动画通过对场景里的对象不断的做图像变换(平移,缩放,旋转,透明度)从而产生动画效果,他是一种渐进式动画,并且View动画支持自定义,帧动画通过顺序播放一系列图片从而产生动画效果,属性动画通过动态的改变属性,来达到动画的目的。View动画(…

大家好,欢迎来到IT知识分享网。

动画的分类

Android 动画可以分别为三种,View动画,帧动画,属性动画。其实帧动画也属于View动画的一种,只不过他的表现形式不同而已,View动画通过对场景里的对象不断的做图像变换(平移,缩放,旋转,透明度)从而产生动画效果,他是一种渐进式动画,并且View动画支持自定义,帧动画通过顺序播放一系列图片从而产生动画效果,属性动画通过动态的改变属性,来达到动画的目的。

View动画(又叫补间动画)

View动画的种类

View动画作用对象是View,它支持四种动画效果,分别为平移动画TranslateAnimation,缩放动画ScaleAnimation,旋转动画RotateAnimation,透明动画 AlphaAnimation,这四种动画既可以通过XML定义,也可以通过代码按定义。建议用XML因为这样效果更好
这里写图片描述

使用View动画首先创建动画的XML, 这个文件路径为 res/anim/fimename.xml,xml是有固定语法的,如下

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
    <!--透明度的起始值-->
    android:fromAlpha="float"
    <!--透明度的结束值-->
    android:toAlpha="float"
    />
    <rotate
    <!--旋转的开始角度-->
    android:fromDegrees="float"
    <!--旋转的轴点的x坐标-->
    android:pivotX="float"
    <!--旋转轴点的y坐标-->
    android:pivotY="float"
    <!--旋转的结束角度-->
    android:toDegrees="float"/>
    <scale
    <!--x方向缩放起始值-->
    android:fromXScale="float"
    <!--y方向缩放起始值-->
    android:fromYScale="float"
    <!--缩放轴的x坐标-->
    android:pivotX="float"
    <!--缩放轴的y坐标-->
    android:pivotY="float"
    <!--x方向缩放结束值-->
    android:toXScale="float"
    <!--y方向缩放结束值-->
    android:toYScale="float"/>
    <translate
    <!--x起始值-->
    android:fromXDelta="float"
    <!--x结束值-->
    android:toXDelta="float"
    <!--y起始值-->
    android:fromYDelta="float"
    <!--y结束值-->
    android:toYDelta="float"/>


</set>

IT知识分享网

AnimationSet :放置在res/anim/目录下一个持有其它动画元素alpha、scale、translate、rotate或者其它set元素的容器

上边简单介绍了xml的属性,除了上面的属性,还有其他常用属性
android:duration=””:动画的持续时间
android:fillAfter=”” :动画结束后view是否停留在结束位置,true为停留,false不停留
例如

IT知识分享网<set xmlns:android="http://schemas.android.com/apk/res/android"
   android:fillAfter="true">
   <translate
       android:fromXDelta="0"
       android:fromYDelta="0"
       android:toXDelta="500"
       android:toYDelta="500"
       android:duration="500"
       />
    <rotate
        android:duration="1000"
        android:fromDegrees="0"
        android:toDegrees="30"
        />
</set>

怎么调用呢

 setContentView(R.layout.activity_donghua);
 Button button = (Button) findViewById(R.id.button);
 Animation animation = AnimationUtils.loadAnimation(this, R.anim.set);
 button.startAnimation(animation);

也可以通过代码设置动画

IT知识分享网AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(1000);
mButton.startAnimation(alphaAnimation);

也可以给动画设置监听

  alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {

                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });

Animation属性详解
android:detachWallpaper: setDetachWallpaper(boolean) 是否在壁纸上运行
android:duration: setDuration(long) 动画持续时间,毫秒为单位
android:fillAfter: setFillAfter(boolean) 控件动画结束时是否保持动画最后的状态
android:fillBefore :setFillBefore(boolean) 控件动画结束时是否还原到开始动画前的状态
android:fillEnabled :setFillEnabled(boolean) 与android:fillBefore效果相同
android:interpolator :setInterpolator(Interpolator) 设定插值器(指定的动画效果,譬如回弹等)
android:repeatCount :setRepeatCount(int) 重复次数
android:repeatMode :setRepeatMode(int) 重复类型有两个值,reverse表示倒序回放,restart表示从头播放
android:startOffset :setStartOffset(long) 调用start函数之后等待开始运行的时间,单位为毫秒
android:zAdjustment :setZAdjustment(int) 表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal

也就是说,无论我们View动画的哪一种都已经具备了这种属性,也都可以设置使用这些属性中的一个或多个。

View动画一些使实用方法

reset(): 重置Animation的初始化
cancel(): 取消Animation动画
start() :开始Animation动画
setAnimationListener(AnimationListener listener) :给当前Animation设置动画监听
hasStarted() :判断当前Animation是否开始
hasEnded() :判断当前Animation是否结束

既然补间动画只能给View使用,那就来看看View中和动画相关的几个常用方法吧,如下:

startAnimation(Animation animation): 对当前View开始设置的Animation动画
clearAnimation() :取消当View在执行的Animation动画

帧动画

顺序播放预先准备好的图片,类似于电影播放,不同于View动画,系统提供了另一个类AnimationDrawable来使用帧动画,帧动画使用比较简单,首先定义一个xml 在res/drawable/filename.xml,如下:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/images1"
        android:duration="500"/>

    <item
        android:drawable="@drawable/images2"
        android:duration="500"/>
    <item
        android:drawable="@drawable/images3"
        android:duration="500"/>
</animation-list>

如何使用

   mButton.setBackgroundResource(R.drawable.zhen_jj);
   AnimationDrawable drawable = (AnimationDrawable) mButton.getBackground();
   drawable.start();

属性动画

属性动画是3.0加入的,和View动画不同,他对作用对象进行了扩展,属性动画可以对任何对象做动画,甚至还可以没有对象,除了作用对象扩展外,属性动画的效果也得到了加强,不像View动画那样只有四种效果,它具有如下动画
ValueAnimator: animator> 放置在res/animator/目录下 在一个特定的时间里执行一个动画
TimeAnimator :不支持/点我查看原因 时序监听回调工具
ObjectAnimator :objectAnimator> 放置在res/animator/目录下 一个对象的一个属性动画
AnimatorSet :set> 放置在res/animator/目录下 动画集合

使用属性动画

属性动画可以对任意对象属性做动画,动画的默认时间是300ms,默认帧率是10ms/帧,可达到的效果是:一段时间内,对象从一个属性达到另一个属性的改变

(1)改变一个对象mButton的translationY 属性,让其沿着y轴平移一段距离

  ObjectAnimator.ofFloat(mButton,"translationY",-mButton.getHeight()).start();

(2)改变一个对象的背景颜色

ObjectAnimator backgroundColor = ObjectAnimator.ofInt(mButton, "backgroundColor", 0XFFFF8080, 0XFF8080FF);
backgroundColor.setDuration(3000);
backgroundColor.setEvaluator(new ArgbEvaluator());
backgroundColor.setRepeatCount(ValueAnimator.INFINITE);
backgroundColor.setRepeatMode(ValueAnimator.REVERSE);
backgroundColor.start();

(3)动画集合,5秒内对旋转,缩放,平移,透明,都进行改变

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

                );
                animatorSet.setDuration(5000).start();

属性动画也可以通过xml进行定义,如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    <!--together 表示 一起播放-->
    <!--sequentially 顺序播放-->
    android:ordering="together |sequentially"
    >

<objectAnimator
    <!--动画时间-->
    android:duration="int"
    <!--表示属性动画作用对象的属性名称-->
    android:propertyName="string"
    <!--表示动画的重复次数,默认0 -1 无限循环-->
    android:repeatCount="int"
    <!--表示动画的重复模式 reverse 表示逆向重复,restart 表示连续重复-->
    android:repeatMode="reverse|restart"
    <!--表示动画的延迟时间,开始多久后,在播放动画-->
    android:startOffset="int"
    <!--表示属性的起始值-->
    android:valueFrom="int|float|color"
    <!--表示属性的结束值-->
    android:valueTo="int|float|color"
    <!--表示android:propertyName所指定的属性类型-->
    android:valueType="floatType|inttype"/>
<animator
    android:duration="int"
    android:repeatCount="int"
    android:repeatMode="reverse|restart"
    android:startOffset="int"
    android:valueFrom="int|float|color"
    android:valueTo="int|float|color"
    android:valueType="floatType|inttype"
    />
    </set>

如何使用

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:ordering="sequentially">

    <objectAnimator
        android:duration="2000"
        android:propertyName="translationX"
        android:valueFrom="-500"
        android:valueTo="0"
        android:valueType="floatType">
    </objectAnimator>

    <set android:ordering="together">
        <objectAnimator
            android:duration="3000"
            android:propertyName="rotation"
            android:valueFrom="0"
            android:valueTo="360"
            android:valueType="floatType">
        </objectAnimator>

        <set android:ordering="sequentially">
            <objectAnimator
                android:duration="1500"
                android:propertyName="alpha"
                android:valueFrom="1"
                android:valueTo="0"
                android:valueType="floatType">
            </objectAnimator>
            <objectAnimator
                android:duration="1500"
                android:propertyName="alpha"
                android:valueFrom="0"
                android:valueTo="1"
                android:valueType="floatType">
            </objectAnimator>
        </set>
    </set>

</set>
AnimatorSet animator = (AnimatorSet) AnimatorInflater.loadAnimator(DonghuaActivity.this, R.animator.set);
animator.setTarget(mButton);
animator.start();

属性动画推荐代码实现,因为代码比较简单,而且很多属性的开始值是需要计算的

插值器和估值器

TimeInterpolator中文翻译为时间插值器,他的作用是根据时间的流逝的百分比计算出当前属性值改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速动画),AccelerateDecelerateInterpolator(加速减速插值器:动画俩头慢正中间快),DecelerateInterpolator(减速插值器:动画越来越慢)等,TypeEvaluator 中文翻译为类型估值算法,也叫估值器,他的作用是根据当前的属性改变的百分比,计算改变后的属性值,系统预置的有ArgbEvaluator(针对color属性),IntEvaluator(针对整型属性),FloatEvaluator(针对浮点型属性),属性动画中,插值器和估值器很重要,他们是实现非匀速动画的重要条件,下面我们举一个例子
他表示一个匀速动画,采用了线性插值器和整型估值算法,在40ms内View的x属性从0到40的变换
这里写图片描述
动画的默认刷帧率为10ms/帧 所以分为5帧进行,我们来考虑第三帧(x=20,t=20ms),当t=20ms的时候,时间流逝的百分比是0.5 (20/40=0.5),意味着现在时间过了一半,那么x应该改变多少呢,这个就由插值器和估值器来计算了,拿线性插值器来说,当时间流逝一半的时候,x改变也应该一半了,即x的改变也是0.5,为什么呢,因为他是匀速动画,下面看他的源码

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

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

很显然插值器的返回值和输入值一样,因此插值器的返回值是0.5,这就意味着x的改变是0.5,这个时候插值器的工作就完成了,具体x变成了什么值,这个需要估值算法来确定,我们来看看整型估值算法的源码

public class IntEvaluator implements TypeEvaluator<Integer> {

    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

算法很简单,他的三个参数分别为,估值小数,开始值和结束值,对应我们的例子就是,0.5 , 0 ,40,根据上面算法,估值器给我们返回的是20

属性动画的监听

属性动画提供了监听器,用于监听动画的播放过程,主要有如下俩个接口,AnimatorListener和AnimatorUpdateListener
AnimatorListener 的定义如下

public static interface AnimatorListener {
       
        void onAnimationStart(Animator animation);

        void onAnimationEnd(Animator animation);
        
        void onAnimationCancel(Animator animation);

        void onAnimationRepeat(Animator animation);
    }

监听动画的开始,结束,取消,重复等,也提供了AnimatorListenerAdapter,他是个适配类,这样我们就可以有选择的实现上面的方法

AnimatorUpdateListener 的定义

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

AnimatorUpdateListener 比较特殊他会监听整个动画的过程,动画由许多帧组成的,每播放一帧,onAnimationUpdate就会调用一次

对任意属性做动画

属性动画要求,动画作用的对象,提供该属性的get和set方法,属性动画根据外界传递的属性的初始值和最终值,以动画的效果多次调用set方法,每次传递给set的值都不一样,确切来说,随着时间的推移,所传递的值越来越接近最终值,我么来总结一下,我们对Object的属性adc做动画,如果想要一次生效,必须满足俩个条件
(1) object必须提供setAbc方法,如果动画的时候没有传递初始值,那么还需提供getAbc,因为系统要去取初始值(如果不满足就Crash’)
(2) Object的setAbc 对属性adb所做的改变,必须通过某种方法反应出来,比如会带来UI的改变这类的(如果不满足,动画无效果但不会Crash’)

假如我们对Button的width属性做动画,其实是没有效果的,虽然Button里有setWidth和getWidth,但是这个setWidth并不是改变视图的大小,通过源码我们可以看出,Button继承TextView,setWidth其实是设置TextView的最大宽度和最小宽度,所以不满足第2点,要解决这类问题,我们有三种方式

(1) 给你的对象加上get和set方法,如果你有权限的话
但是我们很多时候都没有权限这么做,比如你没办法给Button加一个合适的setWidth,因为这是Sdk实现的
(2) 用一个类包装对象,间接提供get和set方法

private void profremAnimator() {
ViewWrapper viewWrapper = new ViewWrapper(mButton);
ObjectAnimator.ofInt(viewWrapper, "width", 0,500).setDuration(5000).start();
    }
private static class ViewWrapper {
        private View mTagert;

        public ViewWrapper(View view) {
            this.mTagert = view;
        }

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

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

(3) 采用ValueAnimator 监听动画过程,自己实现属性的改变
ValueAnimator ,不作用于任何对象,也就是说直接使用它,没有任何效果,他可以对一个值做动画,然后我么你可以监听动画过程,在动画过程中修改我们对象的属性值,这样也相当于我们对象做了动画

 private void profremAnimator1(final View view, final int start, final int end) {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            //持有一个整型估值器,方便下边调用
            IntEvaluator intEvaluator = new IntEvaluator();

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //获取当前动画的进度, 1~100
                int animatedValue = (int) animation.getAnimatedValue();
                Log.d("mmm", "current value=" + animatedValue);

                //获取当前进度占整个动画的比例 浮点型 0~1
                float animatedFraction = animation.getAnimatedFraction();
                //直接调用估值器,通过比例计算宽度,赋值给button
                view.getLayoutParams().width = intEvaluator.evaluate(animatedFraction, start, end);
                view.requestLayout();
            }
        });
        valueAnimator.setDuration(5000).start();
    }

拿上边的例子来说,他会在5000ms中把一个数从0变到100,然后动画的每一帧都会回调到onAnimationUpdate方法,在这个方法可以获取到,当前值所占的比例,然后计算出现在的宽度是多少,比如,当前值是50,比例为0.5(50/100=0.5),假设button起始宽度为100px ,最终宽度为500px,那么button增加的宽度也应该是总宽度的一般,总宽度500-100=400,所以Button应该增加的宽度为 400*0.5=200,那么当前button的宽度为,起始宽度+增加宽度=100+200=300,上面实现很简单,其实就是整型估值器的内部实现,所以不用自己写了,直接用

动画讲解到此为止,谢谢观看

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/7516.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信