复杂动画设计-部分问题说明

339 阅读2分钟

1. ValueAnimator.setFrameDelay

/**
 * The amount of time, in milliseconds, between each frame of the animation. This is a
 * requested time that the animation will attempt to honor, but the actual delay between
 * frames may be different, depending on system load and capabilities. This is a static
 * function because the same delay will be applied to all animations, since they are all
 * run off of a single timing loop.
 *
 * The frame delay may be ignored when the animation system uses an external timing
 * source, such as the display refresh rate (vsync), to govern animations.
 *
 * Note that this method should be called from the same thread that {@link #start()} is
 * called in order to have the new frame delay take effect on that animation. A runtime
 * exception will be thrown if the calling thread does not have a Looper.
 *
 * @param frameDelay the requested time between frames, in milliseconds
 */
public static void setFrameDelay(long frameDelay) {
    AnimationHandler.getInstance().setFrameDelay(frameDelay);
}
  • 前面多次说道动画帧(Frame),什么叫Frame呢?相当于视图动画中的帧动画,也就是每一个单独的页面,类似于胶卷电影中的一格。人眼的可察觉刷新频率是24帧每秒,在低于这个频率的动画中我们看到影像就不是连续的。而熟悉动画中用来指定动画刷新频率的是setFrameDelay()方法,默认情况下它的值是10ms,也就是100帧每秒.
  • 可以试一下能不能降低刷新率,在listener中试验.看设置前后调用次数是否发生变化.可以尽可能的降低监听逻辑调用次数,提升性能.

2. 已经有了 TimeInterpolator ,为什么还需要 TypeEvaluator

  • 在int,float等类型属性的属性动画上,实际无需额外使用 TypeEvaluator .因为动画过程中我们需要的属性值已经自动计算好直接使用即可.
  • 有些自定义的属性,不是简单的数值变化,是'多个属性'的变化,或者现有的TypeEvaluator无法获取当下属性值 ,就需要 自定义TypeEvaluator .通过 evaluate 中的 fraction属性得到当下属性值.

3. ObjectAnimator需要target中包含propertyName的setter方法.且setter方法必须对属性的变化做出正确响应.如果不满足以上条件,有2种解决方式

  1. 使用ValueAnimator.不详述.
  2. 使用包装类,添加对应属性的setter方法,补全'对指定属性变化执行正确响应'逻辑.
    • 摘自<Android开发艺术探索>
    public static class ViewWrapper{
        private View mTarget;
        public ViewWrapper(View target){
            this.mTarget = target;
        }
        public int getWidth(){
            return this.mTarget.getLayoutParams().width;
        }
        public void setWidth(int width){
            this.mTarget.getLayoutParams().width = width;
            this.mTarget.requestLayout();
        }
    }
    
    ViewWrapper wrapper = new ViewWrapper(mButton);
    ObjectAnimator.ofInt(wrapper,"witdth",100,200).start();
    

4. ///