属性动画【Property animation】

第二次看属性动画,结合两本书的介绍和郭神的博客来总结一下。

Android3.0之后的动画系统是 帧动画,属性动画,补间动画三足鼎立的局面。
那么他们各自有各自的优缺点,但是属性动画是相对先进的技术,至少它能解决view移动事件不移动的情况,它还带来了更多丰富的效果和更丰富的接口来开发提升的效率。

那其实属性动画能带来的不只有这些,具体的好处可以在文末的连接参考郭神的博客,大神写的更加详细。(同时本篇里的部分代码借鉴于郭神的代码)

1.ValueAnimator

在说属性动画效果之前必须先讨论这个东西。
ValueAnimator的作用并不是产生动画效果,而是以特定算法来计算属性值,通过得到属性值,Animator就可以对Object进行一系列的动画,除此之外,ValueAnimator对于动画管理,监听器等地方也有所作用。

        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,100);
        valueAnimator.setTarget(textView);
        valueAnimator.setDuration(1000).start();
        valueAnimator.addUpdateListener(new 
        ValueAnimator.AnimatorUpdateListener() {
             @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Float f = (Float) animation.getAnimatedValue();
               //Log打印f
            }
        });

我们需要搞到一个ValueAnimator对象,那么其实是通过静态工厂类返回对象,比如说我们调用的ofFloat方法,这里传入一个可变参数,比如说我们给的(0,100),

    //Android源码
    public static ValueAnimator ofFloat(float... values) {
        ValueAnimator anim = new ValueAnimator();
        anim.setFloatValues(values);
        return anim;
    }

当我们start这个动画之后,并给其添加一个动画的更新监听器,在终端打印下float的值,你可以看到在1000ms的时间内,从0-100的特定规律变化

如果你想实现其他形式的变化可以如下:

 //0->5->3->10的跳跃性变化
ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);  
//整数型变化
ValueAnimator anim = ValueAnimator.ofInt(0, 100); 

当然作为动画数值生成类也是有setRepeat , setRepeatMode之类的方法,主要是对数据进行一些花样的处理(同时也是满足不同的动画效果,这些也是在补间动画上有的)

2.ObjectAnimator

到这里才进入了我们真正的效果阶段,我们真实能看到效果的,展现到屏幕上的是ObjectAnimator,那前面说过,其实ObjectAnimator是基于ValueAnimator的数值变化来完成的,也可以说是ValueAnimator在后面默默地工作,ObjectAnimator才能展示出效果。

同样的ObjectAnimator的用法也是跟ValueAnimator差不多的,通过静态工厂返回对象,通过ofFloat来设置参数,最后设置区间启动动画。

比如下面的textview的透明度从不透明到全透明到不透明。

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
animator.setDuration(5000);  
animator.start();  

ofFloat源码如下

  public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
    }
参数1:Object目标,也就是我们要实现动画的东西,不仅限于view
参数2:propertyName,属性名称,也就是我们要实现什么动画
参数3:可变参数,主要是实现的动画的动画参数

这样的话一个简单的属性动画就实现了。
同样其他动画效果

//旋转360°
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
animator.setDuration(5000);  
animator.start();  
//当前位置平移-500(左移),然后移动回来
float curTranslationX = textview.getTranslationX();  
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);  
animator.setDuration(5000);  
animator.start()

那么更多的效果也是可以用类似的方法来实现的。
具体的有以下几种:

translationX & translationY :X与Y轴的平移效果
rotationX & rotationY & rotation:围绕view本身的旋转效果
PrivotX & PrivotY:围绕着View中心点(默认)旋转缩放的效果
scaleX & scaleY:中心点缩放的动画
alpha:透明度动画

但是我们为什么能用这些动画呢,还记得在之前说过属性动画不仅是用于view的,而是可以用于任何地方,那么这就说明属性动画设计的时候没有view限制,我们可以给第二个参数传任何的值进去,但是前提是对象有get/set方法,什么意思呢,拿textview举例,我们在textview的源码中可以找到setAlpha()方法如下:

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
        ensureTransformationInfo();
        if (mTransformationInfo.mAlpha != alpha) {
            // Report visibility changes, which can affect children, to accessibility
            if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) {
                notifySubtreeAccessibilityStateChangedIfNeeded();
            }
            mTransformationInfo.mAlpha = alpha;
            if (onSetAlpha((int) (alpha * 255))) {
                mPrivateFlags |= PFLAG_ALPHA_SET;
                // subclass is handling alpha - don't optimize rendering cache invalidation
                invalidateParentCaches();
                invalidate(true);
            } else {
                mPrivateFlags &= ~PFLAG_ALPHA_SET;
                invalidateViewProperty(true, false);
                mRenderNode.setAlpha(getFinalAlpha());
            }
        }
    }

具体代码在这里不解释,正是因为有了这个方法,我们的alpha动画才可以生效,所以你大概可以明白,当我们的object木有PropertyName的get/set方法的时候,我们是没法进行动画实现的。

那么其实现在你就明白了属性动画的强大了,它给予你非常大的自定义空间,你可以给任何对象添加你想要的实现。

然后如果你想实现一个动画监听器的话

  objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
             //动画开始
            }
            @Override
            public void onAnimationEnd(Animator animation) {           
             //动画结束 
           }
            @Override
            public void onAnimationCancel(Animator animation) {
            //动画取消
           }
            @Override
            public void onAnimationRepeat(Animator animation) {
            //动画重复 
           }
        });

当然系统还提供了适配器来解决只选择必要的方法重写的功能。

objectAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationRepeat(Animator animation) {
                super.onAnimationRepeat(animation);
            }
        });

3.组合动画

虽然我们已经可以实现简单的动画,但是产品总是会有很多神奇的想法,今天实现这么个动画,明天实现这个动画,各种奇怪的需求,你不得不寻找解决办法,但是在属性动画中,官方也给了相应API来实现,可以说是很不错的。

实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例

那么AnimatorSet.Builder的源码如下:

public class Builder {
        private Node mCurrentNode;
        Builder(Animator anim) {
            mDependencyDirty = true;
            mCurrentNode = getNodeForAnimation(anim);
        }
        public Builder with(Animator anim) {
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addSibling(node);
            return this;
        }
        public Builder before(Animator anim) {
            mReversible = false;
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addChild(node);
            return this;
        }
        public Builder after(Animator anim) {
            mReversible = false;
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addParent(node);
            return this;
        }
       public Builder after(long delay) {
            // setup dummy ValueAnimator just to run the clock
            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
            anim.setDuration(delay);
            after(anim);
            return this;
        }
    }

Builder是构建者,每次调用都会返回builder自身用于继续构建,这四个方法分别是:

  • after(Animator anim) 将现有动画插入到传入的动画之后执行
  • after(long delay) 将现有动画延迟指定毫秒后执行
  • before(Animator anim) 将现有动画插入到传入的动画之前执行
  • with(Animator anim) 将现有动画和传入的动画同时执行

通过这样我们就可以控制动画播放顺序,来实现想要的效果。

        ObjectAnimator animator1 = ObjectAnimator.ofFloat(textView,"translationX",0.0f,200.0f,0f);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(textView,"scaleX",1.0f,2.0f);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(textView,"rotationX",0.0f,90.0f,0f);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(1000);
        set.play(animator1).with(animator2).after(animator3);
        set.start();

4.XML实现

在以前实现动画效果的时候我们可以用xml来实现,当然属性动画也不例外,有了xml代码我们可以节省时间空间,很方便的调用,会达到一个代码的复用,使用之前首先在res中建立animator(这个是为属性动画准备的)文件夹,那么在XML文件中我们一共可以使用如下三种标签:
对应代码中的ValueAnimator
对应代码中的ObjectAnimator
对应代码中的AnimatorSet

  
  
      
      
  
      
          
          
  
          
              
              
              
              
          
      
  
  

这里搬郭神的一段代码来,这是使用xml来完成一个动画集合的效果,当然如果写单个动画只需要写

  
              

一部分。

在java中的调用是这样的

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);  
animator.setTarget(view);  
animator.start();  

首先加载动画文件,绑定视图,最后启动动画。
属性动画的介绍就这么多,肯定不如郭神讲的详细,下面也给了郭神的文章链接,更多的请访问。

参考:http://blog.csdn.net/guolin_blog/article/details/43536355

你可能感兴趣的:(属性动画【Property animation】)