ApiDemos – BouncingBalls分析

本文详细分析了ApiDemos中的BouncingBalls例子,重点讲解了属性动画的使用,包括ObjectAnimator的选择对象和属性、设置时长、时间插值、反复次数和行为、动画控制器以及帧刷新率。还介绍了MyAnimationView的构造函数和onTouchEvent事件,以及如何通过XML定义属性动画。
摘要由CSDN通过智能技术生成

ApiDemos – BouncingBalls分析

 

这个例子主要是介绍属性动画的使用的,关于属性动画的一些关键设定的值,我们在上一篇文章大致描述了一番。另外,在分析这个例子之前,我们需要知道属性动画的类层次关系,这样便于理解和使用。

它的层次关系如下:

 

图1 Animator类继承图

 

BouncingBalls类是一个普通的Activity,它添加了一个自定义的MyAnimationView到主界面中。我们先看这个MyAnimationView的构造函数是怎样的:

public class MyAnimationView extends View {      
        public MyAnimationView(Contextcontext) {
            super(context);
 
            // Animate background color
            // Note that setting the background color will automatically invalidatethe
            // view,so that the animated color, and the bouncing balls, get redisplayed on
            // every frame of the animation.
            ValueAnimator colorAnim =ObjectAnimator.ofInt(this, "backgroundColor", RED, BLUE);
            colorAnim.setDuration(3000);
            colorAnim.setEvaluator(new ArgbEvaluator());
           colorAnim.setRepeatCount(ValueAnimator.INFINITE);
           colorAnim.setRepeatMode(ValueAnimator.REVERSE);
            colorAnim.start();
        }


 

MyAnimationView继承自View类,是个自定义View,它在构造函数里启动了一个属性动画,即colorAnim.start()。

 

这里面用到了一个ObjectAnimator,这个对象动画控制器可以直接作用于某个对象。还记得我们上节讲到的属性动画的几个关键步骤是哪些吗?设置属性动画,必然离不开这几个关键步骤,否则动画是不可能成功的。在本例中这个ObjectAnimator也同样做了这几步:

1)  选定对象(Object)+属性(Property):简称 O + P;

ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", RED, BLUE);

Object = this;

P = “backgroundColor”,这是View的背景色的属性值,也同时说明View中必然存在方法setP()以及getP(),即setBackgroundColor和getBackgroundColor;

 

2)  时长(Duration):简称D;

colorAnim.setDuration(3000);

D = 3000ms=3s

 

3)  时间插值(Time interpolation):简称T;

 

这里我们并没有指定T值,如果没有指定,那么T必须是线性插值,也就是说在某个时间点time,当前的属性值的相对变化位置是 T = time/D;

 

再看,下面的代码,

colorAnim.setEvaluator(new ArgbEvaluator());

那么这个ArgbEvaluator是干什么用的呢?这个ArgbEvaluator就是计算当前属性值的,也即当前View的背景色的哦。我们可以看看ArgbEvaluator()的实现啊:

/**
 * This evaluator can be used to perform typeinterpolation between integer
 * values that represent ARGB colors.
 */
public class ArgbEvaluatorimplements TypeEvaluator {
 
    /**
     * This function returns the calculated in-between value fora color
     * given integers that represent the startand end values in the four
     *bytes of the 32-bit int. Each channel is separately linearly interpolated
     * and the resulting calculated values arerecombined into the return value.
     *
     * @param fraction The fraction fromthe starting to the ending values
     * @param startValue A 32-bit int valuerepresenting colors in the
     * separate bytes of the parameter
     * @param endValue A 32-bit int valuerepresenting colors in the
     * separate bytes of the parameter
     * @return A value that is calculatedto be the linearly interpolated
     * result, derived by separating the startand end values into separate
     * color channels and interpolating eachone separately, recombining the
     * resulting values in the same way.
     */
    public Object evaluate(float fraction, ObjectstartValue, Object endValue) {
        int startInt = (Integer) startValue;
        int startA = (startInt >> 24) & 0xff;
        int startR = (startInt >> 16) & 0xff;
        int startG = (startInt >> 8) & 0xff;
        int startB = startInt & 0xff;
 
        int endInt = (Integer) endValue;
        int endA = (endInt >> 24) & 0xff;
        int endR = (endInt >> 16) & 0xff;
        int endG = (endInt >> 8) & 0xff;
        int endB = endInt & 0xff;
 
        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
                (int)((startR + (int)(fraction * (endR - startR))) << 16) |
                (int)((startG + (int)(fraction * (endG - startG))) << 8) |
                (int)((startB + (int)(fraction * (endB - startB))));
    }
}
 


从上面的代码可以看出,它的作用就是计算当前的颜色值。计算方法本质上讲就是:

当前背景色 = (BLUE – RED) * fraction = (BLUE– RED)* T = (BLUE – RED)*(time/D) = (BLUE – RED) * (time / 3000);

 

你也可以自定义自己的Evaluator,但是返回值必须是属性值的类型才行。

 

4)  反复次数(Repeat Count)和行为(Behavior):简称R&B;

colorAnim.setRepeatCount(ValueAnimator.INFINITE);
colorAnim.setRepeatMode(ValueAnimator.REVERSE);

R = ValueAnimator. INFINITE无限变化哦

B = ValueAnimator.REVERSE动画结束后再反向播放哦

 

5)  动画控制器(Animator):简称A;

A = ObjectAnimator;

 

6)  帧刷新率(Frame refresh delay):简称F;

没有设置哦,那么 F = 10ms,也就是说理论上讲10ms就会刷新一帧,即调用this.setBackgroundColor一次哦。

 

上面6个步骤就是一个属性动画的完整步骤。

当前了这个动画还可以通过XML文件来实现,这个我们最后再讲吧。

 

在这个BouncingBalls界面,手指滑动会产生N多个运动的小球哦。我们来看看MyAnimationView的onTouchEvent事件:

@Override
        public boolean onTouchEvent(MotionEventevent) {
            if (event.getAction() != MotionEvent.ACTION_DOWN &&
                    event.getAction() !=MotionEvent.ACTION_MOVE) {
                return false;
            }
            ShapeHolder newBall =addBall(event.getX(), event.getY());
 
            // Bouncing animation with squash and stretch
            float startY = newBall.getY();
            float endY = getHeight() - 50f;
            float h = (float)getHeight();
            float eventY = event.getY();
            int duration = (int)(500 * ((h - eventY)/h));
            ValueAnimator bounceAnim =ObjectAnimator.ofFloat(newBall, "y", startY, endY);
            bounceAnim.setDuration(duration);
            bounceAnim.setInterpolator(new AccelerateInterpolator());

 

从上面的代码得知,在MOVE事件的时候,创建一个ShapeHolder类型的对象,然后在这个对象上创建它的”y”属性的动画,当然了这个ShapeHolder是自定义的对象,具体是什么大家自己看吧,但是可以肯定的是这个对象一定有一个getY和setY方法。比较新鲜的是设定了时间插值对象:

bounceAnim.setInterpolator(new AccelerateInterpolator());


这个AccelerateInterpolator就是我们上面提到的T值。它的实现如下:

/**
 * An interpolator where the rate of changestarts out slowly and
 * and then accelerates.
 *
 */
public class AccelerateInterpolator implements Interpolator {
    private final float mFactor;
    private final double mDoubleFactor;
 
    public AccelerateInterpolator() {
        mFactor = 1.0f;
        mDoubleFactor = 2.0;
    }
   
    /**
     * Constructor
     *
     * @param factor Degree to which theanimation should be eased. Seting
     *       factor to 1.0f produces a y=x^2 parabola. Increasing factor above
     *       1.0f  exaggerates the ease-in effect (i.e.,it starts even
     *       slower and ends evens faster)
     */
    public AccelerateInterpolator(float factor) {
        mFactor = factor;
        mDoubleFactor = 2 * mFactor;
    }
   
    public AccelerateInterpolator(Contextcontext, AttributeSet attrs) {
        TypedArray a =
           context.obtainStyledAttributes(attrs,com.android.internal.R.styleable.AccelerateInterpolator);
       
        mFactor =a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor,1.0f);
        mDoubleFactor = 2 * mFactor;
 
        a.recycle();
    }
   
    public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }
}
 


上面最主要的方法是getInterpolation()这个方法,这个值返回当前属性值的T值,其中参数input其实就是线性变化百分比,如果直接把input(0.0<= input <=1.0)返回的话,那么属性值的变化是线性的,但是本类顾名思义是一个加速插值类型,所以返回的值类型是input*input,这样看起来就会有加速的功能哦。

 

onTouchEvent()中有一段代码是这样的:

// Sequence the twoanimations to play one after the other
            AnimatorSet animatorSet = new AnimatorSet();
           animatorSet.play(bouncer).before(fadeAnim);
 
            // Start the animation
            animatorSet.start();

 

AnimatorSet是干什么用的,原来这个直译就是动画控制器组合,说白了,可以让N个Animator同时动画,或者一前一后等。把所有的动画集中起来控制哦。

 

好了,上面就是这个例子的主要知识点了哦。

 

下面,我们看看如何在XML中设置属性动画的呢。属性动画的XML文件位置应当放在目录/res/animator/下面,我们以更改背景色为例,创建一个myanimationview_background_change.xml:

 

<?xml version="1.0"encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
       android:propertyName="backgroundColor"
       android:duration="3000"
       android:valueFrom="#FFFF8080"
       android:valueTo="#FF8080FF"
       android:repeatCount="-1"
       android:repeatMode="reverse"
       ></objectAnimator>
 
</set>


 

修改MyAnimationView的构造函数:

public MyAnimationView(Context context) {
            super(context);
 
            // Animate background color
            // Note that setting the background color will automatically invalidatethe
            // view, so that the animated color, and the bouncing balls, getredisplayed on
            // every frame of the animation.
            /*ValueAnimator colorAnim = ObjectAnimator.ofInt(this,"backgroundColor", RED, BLUE);
            colorAnim.setDuration(3000);
            colorAnim.setEvaluator(newArgbEvaluator());
           colorAnim.setRepeatCount(ValueAnimator.INFINITE);
           colorAnim.setRepeatMode(ValueAnimator.REVERSE);
            colorAnim.start();*/
            AnimatorSet colorAnimSet =(AnimatorSet)AnimatorInflater.loadAnimator(context, R.animator.myanimationview_background_change);
            ObjectAnimator colorAnim =(ObjectAnimator)colorAnimSet.getChildAnimations().get(0);
            colorAnim.setTarget(this);
            colorAnim.setEvaluator(new ArgbEvaluator());
            colorAnimSet.start();
        }


 

请下载APIDemos源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值