zoukankan      html  css  js  c++  java
  • Android View动画


    Android的动画模式:tween animation,frame animation和property animation,又叫View Animation,Drawable Animation和Property Animation。前两种是3.0曾经版本号支持的。属性动画是3.0以后支持的。
    Animation和Animator的差别:Animation仅仅是view的绘制效果,但实际属性没有改变。而Animator改变的是view的属性。比方做位移动画。用Animation时view的实际位置没有改变,而Animator能够改变view的位置。
    本文重点介绍属性动画。

    1.Animation

    用Animation能够实现AlphaAnimation,ScaleAnimation,TranslateAnimation,RotateAnimation。


    比方:

            float fromY = 0f;
            float toY = 100f;
            anim = new TranslateAnimation(0.0f, 0.0f, fromY, toY);
            anim.setInterpolator(new LinearInterpolator());
            anim.setDuration(3000);
            anim.setStartOffset(700);
            anim.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
    
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
    
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
    
                }
            });
            view.startAnimation(anim);

    2. TypeEvaluator

    TypeEvaluator提供了一个接口,开发人员能够通过实现该接口自己定义Evaluator。


    眼下系统提供的Evaluator有以下几种:
    ArgbEvaluator,FloatArrayEvaluator,FloatEvaluator,IntArrayEvaluator。IntEvaluator。RectEvaluator,PointFEvaluator等,
    看ArgbEvaluator的实现,我们发现仅仅须要依据我们定义的属性简单的实现evaluate方法就能够了。

    这样我们就能够定义自己的XXEvaluator了。
    依据动画运行的时间跟应用的Interplator,会计算出一个0~1之间的因子。即evalute函数中的fraction參数。

    public class ArgbEvaluator implements TypeEvaluator {
        private static final ArgbEvaluator sInstance = new ArgbEvaluator();
    
        public static ArgbEvaluator getInstance() {
            return sInstance;
        }
    
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            int startInt = (Integer) startValue;
            int startA = (startInt >> 24) & 0xff;
            int startR = (startInt >> 16) & 0xff;
            int startG = (startInt >> 8) & 0xff;
            int startB = startInt & 0xff;
    
            int endInt = (Integer) endValue;
            int endA = (endInt >> 24) & 0xff;
            int endR = (endInt >> 16) & 0xff;
            int endG = (endInt >> 8) & 0xff;
            int endB = endInt & 0xff;
    
            return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
                    (int)((startR + (int)(fraction * (endR - startR))) << 16) |
                    (int)((startG + (int)(fraction * (endG - startG))) << 8) |
                    (int)((startB + (int)(fraction * (endB - startB))));
        }
    }

    样例:

            ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(),
                    0xffffffff, 0xff000000);
            backgroundColor.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
    
                }
                @Override
                public void onAnimationEnd(Animator animation) {
    
                }
            });
            backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int color = (int) animation.getAnimatedValue();
                    mView.setBackgroundColor(color);
                }
            });
            backgroundColor.setInterpolator(new LinearInterpolator());
            backgroundColor.setDuration(500);
            backgroundColor.start();

    3. View的animate()方法

    我们也能够直接使用View的API animate()来做动画,并且还能够几个动画同一时候做哦!


    以下的样例就实现了一个View的X位移、透明度、缩放的动画

            view.animate().translationX(animTranslationXPx)
                    .alpha(0.5f)
                    .setStartDelay(0)
                    .scaleX(0.8f)
                    .scaleY(0.8f)
                    .setUpdateListener(null)
                    .setInterpolator(new AccelerateDecelerateInterpolator())
                    .setDuration(1000)
                    .withEndAction(new Runnable() {
                        @Override
                        public void run() {
    
                        }
                    })
                    .start();

    4. ValueAnimator

    ValueAnimator就是一个数值产生器,他本身不作用于不论什么一个对象。可是能够对产生的值进行动画处理。
    为了实现动画效果,必须为ValueAnimator注冊一个监听器ValueAnimator.AnimatorUpdateListener。该监听器负责更新对象的属性值。在实现这个监听器的时候。能够通过getAnimatedValue()的方法来获取当前帧的值。


    以下样例用ValueAnimator来实现了一个缩放和位移动画:

            final Rect fromRect = ......
            final Rect toRect = ......
    
            final float originScaleX = 1.0f;//(float)fromRect.width() / toRect.width();
            final float originScaleY = 1.0f;//(float)fromRect.height() / toRect.height();
    
            ValueAnimator trans = ValueAnimator.ofFloat(0, 1);
            trans.setInterpolator(new LinearInterpolator());
            trans.setDuration(600);
            trans.addListener(new AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) { }
                @Override
                public void onAnimationRepeat(Animator animation) { }
                @Override
                public void onAnimationEnd(Animator animation) {
    
                }
                @Override
                public void onAnimationCancel(Animator animation) {
    
                }
            });
            trans.addUpdateListener(new AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float percent = (Float)animation.getAnimatedValue();
    
                    float toX = (fromRect.left + percent * (toRect.left - fromRect.left));
                    float toY = (fromRect.top + percent * (toRect.top - fromRect.top));
                    float toR = (fromRect.right + percent * (toRect.right - fromRect.right));
                    float toB = (fromRect.bottom + percent * (toRect.bottom - fromRect.bottom));
                    float scaleX = (float)(toR - toX) / fromRect.width();
                    float scaleY = (float)(toB - toY) / fromRect.height();
                    view.setTranslationX(toX-view.getLeft());
                    view.setTranslationY(toY-view.getTop());
                    view.setScaleX(scaleX*originScaleX);
                    view.setScaleY(scaleY*originScaleY);
                    float alpha = 0 + percent * 1 / (0.8f - 0);
            ......
                }
            });
            trans.start();

    5. ObjectAnimator

    ObjectAnimator继承自ValueAnimator,它会自己主动更新我们定义的属性值,来实现动画的目的。


    以下的样例是用ObjectAnimator来实现X轴位移的动画:

            ObjectAnimator anim = ObjectAnimator.ofFloat(v,View.TRANSLATION_X, newPos);
            anim.setInterpolator(new LinearInterpolator());
            anim.setDuration(500);
            anim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
    
                }
            });
            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
    
                }
            });
            anim.start();

    6. AnimatorSet

    AnimatorSet用于实现多个动画的协同作用,AnimatorSet中有一系列的顺序控制方法:playTogether、playSequentially、animSet.play().with()、defore()、after()等。

    用来实现多个动画的协同工作方式。
    以下的样例用AnimatorSet实现了缩放和位移动画:

            ObjectAnimator trans = ObjectAnimator.ofFloat(view,View.TRANSLATION_X, newPos);
            ObjectAnimator scalex = ObjectAnimator.ofFloat(view, View.SCALE_X, 1.0f, 0.8f);
            ObjectAnimator scaley = ObjectAnimator.ofFloat(view, View.SCALE_Y, 1.0f, 0.8f);
            AnimatorSet animSet = new AnimatorSet();
            animSet.playTogether(scalex, scaley, trans);
            animSet.setDuration(duration);
            animSet.setInterpolator(new LinearInterpolator());
            animSet.addListener(new AnimatorListener() {
    
                @Override
                public void onAnimationCancel(Animator animation) {
                }
    
                @Override
                public void onAnimationEnd(Animator animation) {
                    // do end;
                }
    
                @Override
                public void onAnimationRepeat(Animator animation) {
                }
    
                @Override
                public void onAnimationStart(Animator animation) {
                }
    
            });
            animSet.start();

    关于时间的设置问题:
    假设AnimatorSet设置了setDuration,那么无论子动画有没有设置时间。都要AnimatorSet的时间为准,假设AnimatorSet没有设置。那么子动画以各自的时间为准。当全部动画完毕后调用onAnimationEnd。

    7.使用xml来创建动画

    animation

            final Animation ani = AnimationUtils.loadAnimation(this, R.anim.test);
            ani.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }
                @Override
                public void onAnimationEnd(Animation animation) {
                }
                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
            mView.startAnimation(ani);
    <?xml version="1.0" encoding="utf-8"?>
    <scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:fromXScale="1.0" android:toXScale="0.2"
        android:fromYScale="1.0" android:toYScale="1.0"
        />

    当然也能够用以下的方式做。

    objectAnimator

            Animator ani= AnimatorInflater.loadAnimator(this, R.anim.test);
            ani.setTarget(mView);
            ani.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                }
            });
            ani.start();

    test.xml

    <?xml version="1.0" encoding="utf-8"?>
    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:propertyName="scaleX"
        android:valueFrom="1.0"
        android:valueTo="0.2"
        android:valueType="floatType" >
    </objectAnimator>

    注意两个R.anim.test不要用错,否则会报错。


    通过这个动画也能够看出一般动画和属性动画的差别:
    animation做完动画后属性会恢复原样。也就是说它改变的是View的绘制效果,真正的View的属性并没有改变,animator做完动画后保持动画完毕时的属性不变,说明它把View的属性改变了。

    set

    R.anim.test

    <set xmlns:android="http://schemas.android.com/apk/res/android"
            android:shareInterpolator="false"
            android:zAdjustment="top">
        <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
                android:interpolator="@interpolator/test_alpha"
                android:fillEnabled="true"
                android:fillBefore="false" android:fillAfter="true"
                android:duration="336"/>
        <translate android:fromYDelta="15%" android:toYDelta="0"
                android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
                android:interpolator="@interpolator/test_translate"
                android:duration="336"/>
        <scale android:fromXScale="0.94" android:toXScale="1.0"
                android:fromYScale="0.94" android:toYScale="1.0"
                android:interpolator="@interpolator/test_scale"
                android:duration="336"
                android:pivotX="50%"
                android:pivotY="50%"/>
    </set>

    R.interpolator.test_alpha

    <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:controlX1="0.1"
        android:controlY1="0" android:controlX2="0" android:controlY2="1" />

    Java

            final Animation ani = AnimationUtils.loadAnimation(mActivity, R.anim.test);
            ani.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }
                @Override
                public void onAnimationEnd(Animation animation) {
    
                }
                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });     
            imageView.startAnimation(ani);

    Animator set

    当然也能够用以下的方式实现:
    test_animator.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:ordering="together"
        android:shareInterpolator="false"
        android:zAdjustment="top">
        <objectAnimator
            android:propertyName="alpha"
            android:valueFrom="0.0"
            android:valueTo="1.0"
            android:valueType="floatType"
            android:interpolator="@interpolator/test_alpha"
            android:duration="336"
            />
        <objectAnimator
            android:propertyName="translationY"
            android:valueFrom="@dimen/translation_y"
            android:valueTo="0"
            android:valueType="floatType"
            android:interpolator="@interpolator/test_alpha"
            android:duration="336"
            />
        <set android:ordering="together">
            <objectAnimator
                android:propertyName="scaleX"
                android:valueFrom="0.94"
                android:valueTo="1.0"
                android:valueType="floatType"
                android:interpolator="@interpolator/test_scale"
                android:duration="336"
                />
            <objectAnimator
                android:propertyName="scaleY"
                android:valueFrom="0.94"
                android:valueTo="1.0"
                android:valueType="floatType"
                android:interpolator="@interpolator/test_scale"
                android:duration="336"
                />
        </set>
    </set>

    Java

            Animator animator = AnimatorInflater.loadAnimator(mActivity, R.animator.test_animator);
            animator.setTarget(view);
            animator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {
    
                }
    
                @Override
                public void onAnimationEnd(Animator animation) {
                    end.run();
                }
    
                @Override
                public void onAnimationCancel(Animator animation) {
                    end.run();
                }
    
                @Override
                public void onAnimationRepeat(Animator animation) {
    
                }
            });
            animator.start();

    8.自己定义ObjectAnimator属性

    通常情况下我们使用ObjectAnimator来实现动画效果,能够用以下的方法:

    ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
    anim.setDuration(1000);
    anim.start();

    由于在View中已经实现了alpha属性的动画,那么假设在View中没有实现的属性我们怎样使用ObjectAnimator来做动画呢?
    我们能够用以下的方法:

    ObjectAnimator anim = ObjectAnimator.ofFloat(myTextView, "test", 0f, 1f);
    anim.setDuration(1000);
    anim.start();

    test就代表了View的一个属性,仅仅须要一个类继承View并实现

    public void setTest(float set){
        //to do something
    }

    假设用以下这样仅仅为该属性设置一个属性值,那么还要实现getter的方法:

    ObjectAnimator anim = ObjectAnimator.ofFloat(view, "testt",  1f);
    anim.setDuration(1000);
    anim.start();
    
    public void setTestt(float set){
        mTestt = set;
    }
    
    public float getTestt(){
        return mTestt;
    }

    当然假设view中没有该属性的动画,那么还能够用ValueAnimator来实现。仅仅只是要ValueAnimator.AnimatorUpdateListener接口。自己更新对应的属性值

    9.propertyValuesHolder

    多动画效果的另一种实现方法

        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);
        PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);
        ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ)
            .setDuration(1000)
            .start();

    10.Keyframe

    PropertyValuesHolder的工厂方法里面,除了整形ofInt()、浮点型ofFloat()、Object类型ofObject()之外,另一种:ofKeyframe()。


    Keyframe类型对象由一个time/value对组成,定义了指定时间点的指定值,即关键帧。


    每个keyframe还能够拥有自己的interpolator,控制了前一个关键帧到这一个关键帧之间的时间动画行为。


    Keyframe 对象的构造也用是工厂方法:ofInt(), ofFloat(), or ofObject()。


    Keyframe对象构造完之后就能够用 ofKeyframe()工厂方法来构造PropertyValuesHolder对象。

            Keyframe kf0 = Keyframe.ofFloat(0, 1.0f);
            Keyframe kf1 = Keyframe.ofFloat(0.25f, 0.5f);
            Keyframe kf2 = Keyframe.ofFloat(0.5f, 0f);
            Keyframe kf4 = Keyframe.ofFloat(0.75f, 0.5f);
            Keyframe kf3 = Keyframe.ofFloat(1f, 1.0f);
            PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1, kf2, kf4, kf3);
            ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(mView, pvhRotation);
            anim.setDuration(2000);
            anim.start();

    上述代码的意思为:设置btn对象的width属性值使其:
    開始时 alpha=1.0
    动画開始1/4时 alpha=0.5
    动画開始1/2时 alpha=0
    动画開始3/4时 alpha=0.5
    动画结束时 alpha=1.0
    用以下的代码能够实现相同的效果(上述代码时间值是线性,变化均匀):

            ObjectAnimator oa=ObjectAnimator.ofFloat(mView, "alpha", 1.0f, 0.5f, 0f, 0.5f, 1.0f);
            oa.setDuration(2000);
            oa.start();

    11.Interpolator

    贝塞尔曲线

    一个查看三阶贝塞尔曲线效果的站点
    http://cubic-bezier.com/#.45,0,.21,1

    PathInterpolator

    PathInterpolator是android5.0才開始提供的一种时间时间插值器,和LinearInterpolator。AccelerateDecelerateInterpolator一样用来设置给animator或者animation的,PathInterpolator须要一段起点是(0,0),终点是(1,1)的path路径。
    看它的几个构造函数:
    public PathInterpolator(Path path) :自己定义的Path。可是要保证起点是(0,0)。终点是(1,1)。


    public PathInterpolator(float controlX, float controlY):二阶的贝塞尔曲线,controlX和controlY是控制点的坐标
    public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2)三阶的贝塞尔曲线。(controlX1,controlY1)和(controlX2,controlY2)是两个控制点的坐标。


    还能够通过xml方式定义PathInterpolator:

    ......
    ValueAnimator trans = ValueAnimator.ofFloat(0, 1);
    trans.setInterpolator(enterInterpolator);
    ......
    public Interpolator enterInterpolator;
    enterInterpolator= AnimationUtils.loadInterpolator(context,R.interpolator.enter);

    enter.xml

    <?xml version="1.0" encoding="utf-8"?>
    
    <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:controlX1="0.45"
        android:controlY1="0" android:controlX2="0.34" android:controlY2="1" />

    用android:pathData来描写叙述一个path

    <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
        android:pathData="L0.3,0 C 0.5,0 0.7,1 1, 1" />

    二阶贝塞尔曲线

    <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
        android:controlX1="0.3"
        android:controlY1="0"/>

    加减速引子

    <decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
        android:factor="2.5" />

    android:factor 浮点值。加减速速率,默觉得1

  • 相关阅读:
    2020.2.14
    2020.2.13
    2020.2.12
    2020.2.11
    org.apache.ibatis.binding.BindingException: Parameter '0' not found. Available parameters are [arg1, arg0, param1, param2]
    springboot 项目报错问题的解决
    使用IDEA搭建一个简单的SpringBoot项目——详细过程
    从零开始实现一个简易的Java MVC框架(三)--实现IOC
    使用IDEA创建JavaWeb项目 部署本地tomcat并运行
    ChromePassword
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5209014.html
Copyright © 2011-2022 走看看