属性动画的基础知识可以上郭霖的blog补下。地址:http://blog.csdn.net/guolin_blog/article/details/43536355


以下是自己另附的一些优化策略。
1.使用PropertyValuesHolder
想必大家都这样写过:

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);AnimatorSet animSetXY = new AnimatorSet();animSetXY.playTogether(animX, animY);animSetXY.start();

但是这样写会产生两个ObjectAnimator对象,效率较低,官方建立这样写:

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

这里使用了PropertyValuesHolder,只产生一个ObjectAnimator对象,更加高效。

一个view同时发生多种效果时,建议这种写法。


2.使用Keyframe
同样,我们肯定也这样写过:

AnimatorSet animSet = new AnimatorSet();ObjectAnimator transYFirstAnim = ObjectAnimator.ofFloat(mView, "translationY", 0, 100);ObjectAnimator transYSecondAnim = ObjectAnimator.ofFloat(mView, "translationY", 100, 0);animSet.playSequentially(transYFirstAnim, transYSecondAnim);

产生两个ObjectAnimator对象,一个AnimatorSet,代码繁琐,对象冗杂。
这种情况建议使用Keyframe编写其行为。从词义上来理解Keyframe是关键帧,下面是使用关键帧的例子:

Keyframe k0 = Keyframe.ofFloat(0f, 0); //第一个参数为“何时”,第二个参数为“何地”Keyframe k1 = Keyframe.ofFloat(0.5f, 100);Keyframe k2 = Keyframe.ofFloat(1f, 0);PropertyValuesHolder p = PropertyValuesHolder.ofKeyframe("translationY", k0, k1, k2);ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mView, p);objectAnimator.start();

所以效果就是:
开始时 位置为0;
动画开始1/2时 位置为100;
动画结束时 位置为0。

一个view的单个属性先后发生一系列变化时,建议使用Keyframe达到效果。

总结就是,如果是同一个view的一系列动画,均可使用以上组合方式达到只使用一个ObjectAnimator的效果 。多个view的动画用AnimatorSet进行动画组合和排序,代码架构和执行效率基本能达到最优化。


3.使用AnimatorListenerAdapter代替AnimatorListener
由于AnimatorListener是接口,所以实现它得实现它所有的方法,而我们有时只用到它的个别回调(如:onAnimationStart),使用它会导致代码看起来非常冗杂。而AnimatorListenerAdapter是默认实现了AnimatorListener的一个抽象类,你可以按需要重写其中的方法,代码会优雅一点。


4.使用ViewPropertyAnimator
属性动画的机制已经不是再针对于View而进行设计的了,而是一种不断地对值进行操作的机制,它可以将值赋值到指定对象的指定属性上。
但是,在绝大多数情况下,还是对View进行动画操作的。Android开发团队也是意识到了这一点,于是在Android 3.1系统当中补充了ViewPropertyAnimator这个机制。

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, “alpha”, 0f); animator.start();
等同
textview.animate().alpha(0f);

animate()方法就是在Android 3.1系统上新增的一个方法,这个方法的返回值是一个ViewPropertyAnimator对象。(简明方便)
textview.animate().x(500).y(500).setDuration(5000).setInterpolator(new BounceInterpolator());


5.属性动画其他一些实用方法:(暂时只讲了API 14—Android 4.0及以下的部分)

  1. setStartDelay():可以设置动画开始前的延迟时间。注意:此方法API 14加入;如果给动画添加了AnimatorListener,Listener的onAnimationStart方法会在动画最开始的时候回调,而不是delay一段时间后回调。

  2. isStarted()(API 14)与isRunning():这个得与setStartDelay()放在一起讲,也就是说,当动画在delay中并没有真正开始时,isStarted返回false,而isRunning返回true。也就是,isRunning的周期是大于isStarted的。

  3. cancel()与end():cancel方法会立即停止动画,并且停留在当前帧。end方法会立即停止动画,并且将动画迅速置到最后一帧的状态。

  4. setupStartValues()与setupEndValues():设置动画进行到的当前值为开始值(结束值)。示例如下:

以下这个示例中,当view移动了2.5s的时候,cancel当前动画,并重新设定起始位置为当前位置,结束位置为400,再开始此动画。

final ObjectAnimator o = ObjectAnimator.ofFloat(mTextView, "x", 0, 500);o.setDuration(5000);o.start();mTextView.postDelayed(new Runnable() {      @Override      public void run() {           if (o.isRunning()) {                o.cancel();            }            o.setupStartValues();            o.setFloatValues(400);            o.start();      }},2500);

6.做一个属性动画的方式:(摘自Android开发艺术探索)
1.给你的对象加上get和set方法,前提是你有权限。
2.用一个类来包装原始对象,间接为其提供get和set方法。

    /**     * 用一个类来包装原始对象,间接为其提供get和set方法。     */    private static class ViewWrapper {        private View mTarget;        public ViewWrapper(View target) {            mTarget = target;        }        public int getWidth() {            return mTarget.getLayoutParams().width;        }        public void setWidth(int width) {            mTarget.getLayoutParams().width = width;            mTarget.requestLayout();        }    }    /**     * TextView不能直接设置width,这里即采用了包装的方式,对textview的width进行属性动画     */    private void animViewWidthByWidth() {        ViewWrapper wrapper = new ViewWrapper(mTextView);        ObjectAnimator widthAnim = ObjectAnimator.ofObject(wrapper, "width", new IntEvaluator(), mTextView2.getWidth(), mTextView2.getWidth() * 2);        widthAnim.setDuration(1000);        widthAnim.setRepeatCount(100);        widthAnim.start();    }

3.采用ValueAnimator,监听动画过程,自己实现属性的改变。

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);anim.setDuration(300);anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    @Override    public void onAnimationUpdate(ValueAnimator animation) {        float currentValue = (float) animation.getAnimatedValue();        //此处即可根据currentValue的值自己监听过程,实现计算。        Log.d("TAG", "cuurent value is " + currentValue);    }});anim.start();

7.哪些线程能做属性动画
属性动画的start()方法,首先就有判定:

private void start(boolean playBackwards) {        if (Looper.myLooper() == null) {            throw new AndroidRuntimeException("Animators may only be run on Looper threads");        }    ......}

说明,需要有Looper的线程才可以做属性动画。很明显,Android原生环境中,主线程和HandlerThread是可以做属性动画的,当然,也可以自己实现一个有Looper的Thread。


8.属性动画的内存泄露问题
许多时候用到了无限循环的动画,我们会这样写:animator.setRepeatCount(ValueAnimator.INFINITE);
这样写如果没有及时取消,会导致此属性动画持有被动画对象的引用而导致内存泄露,故在activity生命周期结束时,如onDestroy方法中,及时的cancel掉这种动画。
补间动画无此问题,它是给view做动画,在view的onDetachedFromWindow方法会取消掉动画,所以不会导致内存泄露。

更多相关文章

  1. Android SVG矢量资源的使用方法
  2. android图片压缩的3种方法实例
  3. Android Selector和Shape的使用方法
  4. android内核编译方法
  5. Android矢量动画-VectorDrawable
  6. APP开发实战85-帧动画
  7. 实现android启动界面字体的动画效果

随机推荐

  1. android常用控件(一)- TextView、EditView
  2. ListView中的Item项中有Button按钮时,setO
  3. [转载]Android开发真实谎言:个人无空间 无
  4. Android(安卓)Studio 的 build 过程
  5. Android之AVD中data目录问题
  6. Android(安卓)Jni开发之Android(安卓)Stu
  7. Android中ImageView无法居中的问题
  8. 在cmd环境下创建、编译、打包android应用
  9. 使用jenkins自动上传IOS,android到阿里云
  10. Android代码优化——使用Android(安卓)li