zoukankan      html  css  js  c++  java
  • 属性动画总结(Property Animation)

    一、概述

      属性动画可以作用在View的属性上,对属性进行修改,而且不要求对应的属性一定是有显示效果的。

    二、属性动画的实现方式

      1、基础的类Animator

      Animator是一个抽象类,是属性动画的基础类。不直接使用该类。

      2、ObjectAnimator,继承自ValueAnimator

      使用起来比较方便的是ObjectAnimator,可以使用ObjectAnimator直接指定需要修改的view,要修改的属性,值的变化范围。  

      ObjectAnimator.ofFloat(view, "rotationX", 0.0F, 360.0F)
             .setDuration(500)
             .start();  

      通过上面的代码,就可以让View动起来,十分方便。ObjectAnimator不止有ofFloat方法,还有ofInt,ofArgb等方法,都可以比较方便的绑定View和对应的属性。

      3、ValueAnimator,继承自Animator

      是ObjectAnimator的父类。它不能绑定到具体的属性上,而且没有重写setTarget方法,而Animator中的setTarget方法为空。所以ValueAnimator实际上没有设置View和对应的属性。这就要求使用者自己获取变化的值,并将值赋给具体View对象的属性。

      当然,ValueAnimator其实也十分方便,只需要加上监控事件,在监控的事件中处理相关赋值就可以了。

         ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight  
                    - mBlueBall.getHeight());  
            animator.setDuration(1000).start();  
            animator.addUpdateListener(new AnimatorUpdateListener()  
            {  
                @Override  
                public void onAnimationUpdate(ValueAnimator animation)  
                {  
                    mBlueBall.setTranslationY((Float) animation.getAnimatedValue());  
                }  
            }); 

      可以为ValueAnimator设置重复的次数(setRepeatCount)和重复的模式(setRepeatMode),重复的模式可以是(RESTART)或者(REVERSE)。

      4、AnimatorSet,继承自Animator

      如果想要在View上实现多个动画效果,可以借助于AnimatorSet。如果多个动画同时执行,可以使用AnimatorSet.playTogether方法;如果多个动画按顺序执行,可以使用AnimatorSet.playSequentially方法;如果多个动画没有统一的执行顺序,AnimatorSet提供了play,with,before,after来设置多个动画执行的顺序。

      

      5、PropertyValuesHolder

      PropertyValuesHolder是属性(Property)和值(Value)的对应。ValueAnimator和ObjectAnimator对应的ofInt、ofFloat等都是借助于PropertyValuesHolder来实现的。

      对于在View上实现多个动画效果的要求,也可以使用PropertyValuesHolder来实现。ValueAnimator和ObjectAnimator都提供了方法,可以传入多个PropertyValuesHolder对象,来实现在多个属性上同时产生动画效果的要求。  

         PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
            PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
            PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("rotationX", 0f, 180, 360f);
            ObjectAnimator.ofPropertyValuesHolder(iv_src, pvhX, pvhY, pvhZ).setDuration(2000).start();  

      6、xml

      也可以使用xml文件来定义属性函数,然后在程序中使用AnimatorInflater.loadAnimator方法加载属性动画。xml中,可以使用<set>、<objectAnimator>。

    三、监听类

      1、AnimatorUpdateListener

      在ValueAnimator的时候提到了这个监听类。它在计算的值发生改变的时候回调,只包含一个方法。是ValueAnimator中定义的内部类。

        /**
         * Implementors of this interface can add themselves as update listeners
         * to an <code>ValueAnimator</code> instance to receive callbacks on every animation
         * frame, after the current frame's values have been calculated for that
         * <code>ValueAnimator</code>.
         */
        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);
    
        }

      2、AnimatorListener

      在属性动画的开始、结束、取消、重复的时候回调,在Animator中定义的内部类。

        /**
         * <p>An animation listener receives notifications from an animation.
         * Notifications indicate animation related events, such as the end or the
         * repetition of the animation.</p>
         */
        public static interface AnimatorListener {
            /**
             * <p>Notifies the start of the animation.</p>
             *
             * @param animation The started animation.
             */
            void onAnimationStart(Animator animation);
    
            /**
             * <p>Notifies the end of the animation. This callback is not invoked
             * for animations with repeat count set to INFINITE.</p>
             *
             * @param animation The animation which reached its end.
             */
            void onAnimationEnd(Animator animation);
    
            /**
             * <p>Notifies the cancellation of the animation. This callback is not invoked
             * for animations with repeat count set to INFINITE.</p>
             *
             * @param animation The animation which was canceled.
             */
            void onAnimationCancel(Animator animation);
    
            /**
             * <p>Notifies the repetition of the animation.</p>
             *
             * @param animation The animation which was repeated.
             */
            void onAnimationRepeat(Animator animation);
        }

      3、AnimatorPauseListener

      在属性动画暂停、继续执行的时候回调,在Animator类中定义的内部类。

        /**
         * A pause listener receives notifications from an animation when the
         * animation is {@link #pause() paused} or {@link #resume() resumed}.
         *
         * @see #addPauseListener(AnimatorPauseListener)
         */
        public static interface AnimatorPauseListener {
            /**
             * <p>Notifies that the animation was paused.</p>
             *
             * @param animation The animaton being paused.
             * @see #pause()
             */
            void onAnimationPause(Animator animation);
    
            /**
             * <p>Notifies that the animation was resumed, after being
             * previously paused.</p>
             *
             * @param animation The animation being resumed.
             * @see #resume()
             */
            void onAnimationResume(Animator animation);
        }

      AnimatorListener和AnimatorPauseListener有一个共同的实现类——AnimatorListenerAdapter 。这个类实现了两个接口的所有方法,但是它是一个抽象类,它实现的方法都是空方法,所以没有任何意义。只是如果我们想继承AnimatorListener或者AnimatorPauseListener,但是不想实现所有方法时,使用AnimatorListenerAdapter会很方便。

    四、属性动画的其他功能

      1、Interpolator

      Interpolator表示变化率。它可以把输入的匀速的变化转换成加速、减速等不同的变化率。Android提供了以下Interpolator的实现类:    

    •   AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速
    •   AccelerateInterpolator  在动画开始的地方速率改变比较慢,然后开始加速
    •   AnticipateInterpolator 开始的时候向后然后向前甩
    •   AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值
    •   BounceInterpolator   动画结束的时候弹起
    •   CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
    •   DecelerateInterpolator 在动画开始的地方快然后慢
    •   LinearInterpolator   以常量速率改变
    •   OvershootInterpolator    向前甩一定值后再回到原来位置

      如果上面的实现类仍然不能满足具体的场景,可以自己实现Interpolator,只需要实现float getInterpolation(float input)方法就可以了。

      Animator提供setInterpolator(TimeInterpolator)方法用于设置变化率。而实际上Interpolator接口就直接继承了TimeInterpolator接口,并且没有新增加任何方法或常量等信息。所以Interpolator和TimeInterpolator完全等价。

      Animation(补间动画)及其子类,包含方法setInterpolator(Interpolator),所以Android提供的这些变化率实现类同样适用于补间动画。

      2、TypeEvaluator

      类型估值,用于计算并返回属性值。

      TypeEvaluator的定义如下:

    public interface TypeEvaluator<T> {
    
        public T evaluate(float fraction, T startValue, T endValue);
    
    }

      3、我个人的理解是这样,首先通过Interpolator将匀速的变化变成自己想要的变化率,然后再使用TypeEvaluator将这个变化率转换成自己想要的数据(可能是位置对应的Point,或者其他结构的数据(比如,把位置信息和alpha值一起组装成一个类,表示透明度和位置有明确的相关性),甚至可以是按照某种规则实现的boolean也未尝不可,如此等等的逻辑可以在这里实现)。

      那现在有一个问题,既然Interpolator和TypeEvaluator都是计算值,为什么不把二者合在一起?个人认为可以这样理解,这包含了一种解耦的思想。Interpolator表示速率的变化,是匀速的,是越来越快的,还是先快后慢的等等;而TypeEvaluator则用于计算View的实际状态。两者分开之后,不但在开始设计的时候降低了复杂度,而且可以达到更好的扩展性。如果想要调整变化率,修改Interpolator,如果想要修改View的显示规则,则修改TypeEvaluator。  

            ValueAnimator valueAnimator = new ValueAnimator();  
            valueAnimator.setDuration(3000);  
            valueAnimator.setObjectValues(new PointF(0, 0));  
            valueAnimator.setInterpolator(new LinearInterpolator());  
            valueAnimator.setEvaluator(new TypeEvaluator<PointF>()  
            {  
                // fraction = t / duration  
                @Override  
                public PointF evaluate(float fraction, PointF startValue,  
                        PointF endValue)  
                {  
                    Log.e(TAG, fraction * 3 + "");  
                    // x方向200px/s ,则y方向0.5 * 10 * t  
                    PointF point = new PointF();  
                    point.x = 200 * fraction * 3;  
                    point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);  
                    return point;  
                }  
            });  
      
            valueAnimator.start();  
            valueAnimator.addUpdateListener(new AnimatorUpdateListener()  
            {  
                @Override  
                public void onAnimationUpdate(ValueAnimator animation)  
                {  
                    PointF point = (PointF) animation.getAnimatedValue();  
                    mBlueBall.setX(point.x);  
                    mBlueBall.setY(point.y);  
      
                }  
            }); 

    参考: Android 属性动画(Property Animation) 完全解析 (上)

  • 相关阅读:
    阿里消息队列中间件 RocketMQ 源码分析 —— Message 拉取与消费(上)
    数据库中间件 ShardingJDBC 源码分析 —— SQL 解析(三)之查询SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(六)之删除SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(五)之更新SQL
    消息队列中间件 RocketMQ 源码分析 —— Message 存储
    源码圈 300 胖友的书单整理
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 路由(一)分库分表配置
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(四)之插入SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 路由(二)之分库分表路由
    C#中Math类的用法
  • 原文地址:https://www.cnblogs.com/huanyou/p/5811033.html
Copyright © 2011-2022 走看看