深入分析Android动画(二)
上回书说到Android动画的分类以及基本使用,这会书主要说Android属性动画的原理,对于View动画的原理本篇不做深入分析。对于Android动画的基础请看深入分析Android动画(一)
我们先来看一个需求:要求对一个Button做动画,要求让其宽度从原始宽度增加到500px。这也太简单了,于是我们的主人公鸣人不假思索的写下了如下的代码
1 Button mButton = (Button) findViewById(R.id.button); 2 ObjectAnimator.ofInt(mButton,"width",500).setDuration(1000).start();
程序正常运行,借下来鸣人就分析了上述代码实现的原理,通过研究鸣人惊奇的发现了以下规则:
- 属性动画要求动画的作用对象提供该属性的get和set方法,
- 属性的改变必须通过某种方法反映出来,比如会带来UI的修改之类的
以上的条件缺一不可
这时鸣人又想到一个问题如果想要对一个对象的属性做动画,但是属性又没有对应的get和set方法怎么办呢??
通过研究发现有如下三种解决办法:
- 给你的对象加上get和set方法,如果你有权限的话。而这个方法对于Android SDK内部实现的类就不可行,这个方法是最简单的,但是往往是不可行的。
- 用一个类包装原始对象,间接为其提供get和set方法
- 采用ValueAnimator,监听动画过程,自己实现属性的改变
对于方法2和方法3下面给出例子,仍以上面Button的宽度动画作为需求
方法2:
1 mButton = (Button) findViewById(R.id.button); 2 ObjectAnimator.ofInt(new ViewWrapper(mButton),"width",500).setDuration(1000).start(); 3 4 private class ViewWrapper{ 5 private View mTarget; 6 7 public ViewWrapper(View mTarget) { 8 this.mTarget = mTarget; 9 } 10 11 12 public int getWidth() { 13 return mTarget.getLayoutParams().width; 14 } 15 16 public void setWidth(int width) { 17 mTarget.getLayoutParams().width = width; 18 mTarget.requestLayout(); 19 } 20 }
方法3:
1 mButton = (Button) findViewById(R.id.button); 2 performAnimate(mButton, mButton.getWidth(), 500); 3 4 5 6 private void performAnimate(final View target, final int start, final int end) { 7 8 ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100); 9 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 10 11 // 持有一个IntEvaluator对象,方便下面估值的时候使用 12 private IntEvaluator mEvaluator = new IntEvaluator(); 13 14 @Override 15 public void onAnimationUpdate(ValueAnimator animator) { 16 // 获得当前动画的进度值,整型,1-100之间 17 int currentValue = (Integer) animator.getAnimatedValue(); 18 Log.d(TAG, "current value: " + currentValue); 19 20 // 获得当前进度占整个动画过程的比例,浮点型,0-1之间 21 float fraction = animator.getAnimatedFraction(); 22 // 直接调用整型估值器通过比例计算出宽度,然后再设给Button 23 target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end); 24 target.requestLayout(); 25 } 26 }); 27 28 valueAnimator.setDuration(5000).start(); 29 }