属性动画简单应用

来源:互联网 发布:matlab r2013a mac 编辑:程序博客网 时间:2024/05/16 05:47

属性动画就是不断改变view相应的属性值达到动画的效果。它改变的就是view的属性,所以在动画结束之后不会回到初始的状态。通过属性动画我们可以改变要实现动画效果的view的属性值,只要这个view有相应的属性就可以更改,比如高度、宽度、透明度和翻转等等。

比较常用的就是ObjectAnimator,当我们想多个动画同时执行或者先后的执行时候我们就会用到AnimatorSet。我们也可以对动画进行监听,通过addListener实现对动画的监听。

以下有几个动画效果,我先暂时记录再有其他的动画我再往里面添加:



可以看到红点往左移动的过程中红点变大当到达最左边又往右移动并逐渐变小。

利用ObjectAnimator实现:

     float x = ivCha.getX();        ObjectAnimator an1 = ObjectAnimator.ofFloat(ivCha,"scaleX",1f,2f);        ObjectAnimator an2 = ObjectAnimator.ofFloat(ivCha,"scaleY",1f,2f);            ObjectAnimator an3 = ObjectAnimator.ofFloat(ivCha,"x",x,0f,x);        ObjectAnimator an5 = ObjectAnimator.ofFloat(ivCha,"scaleX",2f,1f);        ObjectAnimator an6 = ObjectAnimator.ofFloat(ivCha,"scaleY",2f,1f);        AnimatorSet animatorSet = new AnimatorSet();        animatorSet.setDuration(1000);        animatorSet.playTogether(an1,an2,an3);        animatorSet.playTogether(an5,an6);        animatorSet.start();
ivCha就是红点的引用。
我们通过AnimatorSet的playTogether方法可以使动画同时执行,也可以通过animatorSet.play(an1).with(an2)使两个动画同时执行,同样的通过animatorSet.play(an2).after(an3)决定执行的顺序。


这个动画是通过更改GridView父控件的高度属性来达到下拉的动画效果。这时候就用到了另一个动画监听:addUpdateListener,它可以通过一开始设置的数值实时的回调属性值,我们通过回调的属性值来设置view的高度就达到了这个效果。

ObjectAnimator an1 = ObjectAnimator.ofFloat(llParents,"xx",200f,screenHeight);        an1.setDuration(500);       an1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {           @Override           public void onAnimationUpdate(ValueAnimator valueAnimator) {               float animatedValue = (float) valueAnimator.getAnimatedValue();               RelativeLayout.LayoutParams ll = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);               ll.height = (int) animatedValue;               llParents.setLayoutParams(ll);           }       });        an1.start();

其中"xx"就是随便写的,200是初始值,而screenHeight是屏幕高度,通过监听器我们拿到了回调的animateValue,然后这时我们通过动态布局将值设置给view的高度。


我们随处可以见的一种动画就是有一个条目从屏幕上面或者下面 滑到最低端或者最上端,我们也可以通过属性动画来实现。

最开始点击按钮条目从没有到有的过程中这时候用到了动画监听事件,来看一下代码:

ObjectAnimator animator = ObjectAnimator.ofFloat(llBelow,"translationY",100,0);        animator.setDuration(500);          animator.addListener(new Animator.AnimatorListener() {          @Override          public void onAnimationStart(Animator animator) {              if (llBelow.getVisibility()==View.GONE)              llBelow.setVisibility(View.VISIBLE);          }          @Override          public void onAnimationEnd(Animator animator) {          }          @Override          public void onAnimationCancel(Animator animator) {          }          @Override          public void onAnimationRepeat(Animator animator) {          }      });        animator.start();

如果嫌addListener里面的回调方法很多用不到这么多时候我们可以采用newAnimatorListenerAdapter()来选取自己想要的方法。

看起来很简单,通过ObjectAnimator设置好y轴方向上的移动从100 到0 ,这个0不是代表屏幕最上面的位置,而是你在xml布局中条目放在什么哪里的位置,条目我是让其显示在最下面,并且让条目隐藏。条目的高度是100px,所以ObjectAnimator里面的参数就是动图的效果。 利用onAnimationStart(Animator animator)回调方法 当开始动画的时候我们就让条目显示这样就能看到动画效果了。

条目隐藏的代码也很简单:

  ObjectAnimator animator = ObjectAnimator.ofFloat(llBelow,"translationY",0,100);        animator.setDuration(500);        animator.start();

--------------------------------------------------------------------------------

属性动画可以改变view的属性,现在我有一个button我想改变她的宽度。一开始我直接这么做:

  ObjectAnimator animator = ObjectAnimator.ofInt(button,"width",500);        animator.setDuration(500);        animator.start();


但是最后是没有效果的,

属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据你传递的该熟悉的初始值和最终值,以动画的效果多次去调用set方法,每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。总结一下,你对object的属性xxx做动画,如果想让动画生效,要同时满足两个条件:

1. object必须要提供setXxx方法,如果动画的时候没有传递初始值,那么还要提供getXxx方法,因为系统要去拿xxx属性的初始值(如果这条不满足,程序直接Crash)

2. object的setXxx对属性xxx所做的改变必须能够通过某种方法反映出来,比如会带来ui的改变啥的(如果这条不满足,动画无效果但不会Crash)

以上条件缺一不可

那么为什么我们对Button的width属性做动画没有效果?这是因为Button内部虽然提供了getWidth和setWidth方法,但是这个setWidth方法并不是改变视图的大小,它是TextView新添加的方法,View是没有这个setWidth方法的,由于Button继承了TextView,所以Button也就有了setWidth方法。

我们可以看一下getwidth()和setWideht()的源码:


/**  * Makes the TextView exactly this many pixels wide.  * You could do the same thing by specifying this number in the  * LayoutParams.  *  * @see #setMaxWidth(int)  * @see #setMinWidth(int)  * @see #getMinWidth()  * @see #getMaxWidth()  *  * @attr ref android.R.styleable#TextView_width  */  @android.view.RemotableViewMethod  public void setWidth(int pixels) {      mMaxWidth = mMinWidth = pixels;      mMaxWidthMode = mMinWidthMode = PIXELS;        requestLayout();      invalidate();  }    /**  * Return the width of the your view.  *  * @return The width of your view, in pixels.  */  @ViewDebug.ExportedProperty(category = "layout")  public final int getWidth() {      return mRight - mLeft;  } 

从源码可以看出,getWidth的确是获取View的宽度的,而setWidth是TextView和其子类的专属方法,它的作用不是设置View的宽度,而是设置TextView的最大宽度和最小宽度的,这个和TextView的宽度不是一个东西,具体来说,TextView的宽度对应Xml中的android:layout_width属性,而TextView还有一个属性android:width,这个android:width属性就对应了TextView的setWidth方法。好吧,我承认我的这段描述有点混乱,但事情的确是这个样子的,而且我目前还没发现这个android:width属性有啥重要的用途,感觉好像没用似的,这里就不深究了,不然就偏离主题了。总之,TextView和Button的setWidth和getWidth干的不是同一件事情,通过setWidth无法改变控件的宽度,所以对width做属性动画没有效果。

那我想实现宽度增加有人想到用

  ObjectAnimator animator = ObjectAnimator.ofInt(button,"scaleX",500);        animator.setDuration(500);        animator.start();

这个不是我想要的效果,button宽度是被拉伸里面的文字也被拉伸了。


之前我写过利用监听器改变view的高度那我用那个方法试试:

ObjectAnimator animator = ObjectAnimator.ofInt(button,"width",500);        animator.setDuration(500);        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator valueAnimator) {                int animatedValue = (int) valueAnimator.getAnimatedValue();                RelativeLayout.LayoutParams ll = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);                ll.width = (int) animatedValue;                button.setLayoutParams(ll);            }        });        animator.start();

可以看到用这个方法虽然宽度增加了但是它的位置改变了 变成了在左上角,如何用监听器的方法那就多写了很多代码也比较麻烦。针对这种遇到view没有的setXXX()方法的时候Google告诉我们有3中解决方法:

1. 给你的对象加上get和set方法,如果你有权限的话

2. 用一个类来包装原始对象,间接为其提供get和set方法

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

第一个权限很好理解你可以自己加上set和get方法,但是有很多源码的东西比如button我们就不容易操作。那第二种就是用一个累包装原始view,给它间接地添加set和get方法:

private void init6() {        ViewAnimator viewAnimator = new ViewAnimator(button);        ObjectAnimator animator = ObjectAnimator.ofInt(viewAnimator,"width",500);        animator.setDuration(500);        animator.start();    }    class ViewAnimator {        private View mTarget;        public ViewAnimator(View view){            this.mTarget = view;        }        public int getWidth(){            return mTarget.getLayoutParams().width;        }        public void setWidth(int width){            mTarget.getLayoutParams().width = width;            mTarget.requestLayout();        }    }

这回可以看到正确的实现了动画效果。

还有第三种方法就是使用ValueAnimator,ValueAnimator本身不作用于任何对象,也就是说直接使用它没有任何动画效果。它可以对一个值做动画,然后我们可以监听其动画过程,在动画过程中修改我们的对象的属性值,这样也就相当于我们的对象做了动画。

    private void performAnimate(final View target, final int start, final int end) {        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {            //持有一个IntEvaluator对象,方便下面估值的时候使用            private IntEvaluator mEvaluator = new IntEvaluator();            @Override            public void onAnimationUpdate(ValueAnimator animator) {                //获得当前动画的进度值,整型,1-100之间                int currentValue = (Integer)animator.getAnimatedValue();                Log.d(TAG, "current value: " + currentValue);                //计算当前进度占整个动画过程的比例,浮点型,0-1之间                float fraction = currentValue / 100;                //直接调用整型估值器通过比例计算出宽度,然后再设给Button                target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);                target.requestLayout();            }        });        valueAnimator.setDuration(5000).start();    }    @Override    public void onClick(View v) {        if (v == mButton) {            performAnimate(mButton, mButton.getWidth(), 500);        }    }
它会在5000ms内将一个数从1变到100,然后动画的每一帧会回调onAnimationUpdate方法,在这个方法里,我们可以获取当前的值(1-100),根据当前值所占的比例(当前值/100),我们可以计算出Button现在的宽度应该是多少,比如时间过了一半,当前值是50,比例为0.5,假设Button的起始宽度是100px,最终宽度是500px,那么Button增加的宽度也应该占总增加宽度的一半,总增加宽度是500-100=400,所以这个时候Button应该增加宽度400*0.5=200,那么当前Button的宽度应该为初始宽度+ 增加宽度(100+200=300)。

0 0
原创粉丝点击