美文网首页
属性动画【Property animation】

属性动画【Property animation】

作者: 做梦枯岛醒 | 来源:发表于2017-10-09 22:29 被阅读41次

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

    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文件中我们一共可以使用如下三种标签:
    <animator> 对应代码中的ValueAnimator
    <objectAnimator> 对应代码中的ObjectAnimator
    <set> 对应代码中的AnimatorSet

    <set xmlns:android="http://schemas.android.com/apk/res/android"  
        android:ordering="sequentially" >  
      
        <objectAnimator  
            android:duration="2000"  
            android:propertyName="translationX"  
            android:valueFrom="-500"  
            android:valueTo="0"  
            android:valueType="floatType" >  
        </objectAnimator>  
      
        <set android:ordering="together" >  
            <objectAnimator  
                android:duration="3000"  
                android:propertyName="rotation"  
                android:valueFrom="0"  
                android:valueTo="360"  
                android:valueType="floatType" >  
            </objectAnimator>  
      
            <set android:ordering="sequentially" >  
                <objectAnimator  
                    android:duration="1500"  
                    android:propertyName="alpha"  
                    android:valueFrom="1"  
                    android:valueTo="0"  
                    android:valueType="floatType" >  
                </objectAnimator>  
                <objectAnimator  
                    android:duration="1500"  
                    android:propertyName="alpha"  
                    android:valueFrom="0"  
                    android:valueTo="1"  
                    android:valueType="floatType" >  
                </objectAnimator>  
            </set>  
        </set>  
      
    </set>  
    

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

    <objectAnimator  
                    android:duration="1500"  
                    android:propertyName="alpha"  
                    android:valueFrom="0"  
                    android:valueTo="1"  
                    android:valueType="floatType" >  
                </objectAnimator>  
    

    一部分。

    在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】

          本文链接:https://www.haomeiwen.com/subject/vtxmyxtx.html