当前位置: 代码迷 >> Android >> 《Android卡通片高手成长记》跳跳球效果
  详细解决方案

《Android卡通片高手成长记》跳跳球效果

热度:78   发布时间:2016-04-24 11:51:41.0
《Android动画高手成长记》跳跳球效果

在介绍本文动画效果实现之前,先来介绍属性动画相关的几个知识点。

  1. ValueAnimator与ObjectAnimator。
  2. Interpolator插值器与TypeEvaluator估值器。

在Android3.0之前,系统提供了两种动画效果实现方式,帧动画frame-by-frame animation和补间动画tweened animation。帧动画就是类似电影播放一样,将整部影片拆分成一片片的然后连贯起来播放。补间动画则可以实现对view的缩放、平移、旋转等操作。在3.0之后,出现了一种新的动画模式称为属性动画property animation。

属性动画产生的原因

属性动画的出现不是用来替代补间动画的,而是用来解决补间动画所不能够完成的事件的。如果我们的需求超出了操控view的旋转、缩放、平移等操作范围,那么我们就需选择属性动画去实现了。那么属性动画可以做到哪些补间动画做不到的事情呢?下面列举几点,当然属性动画的功能很强大,不仅限于我列举的几点。

  1. 属性动画可以做到对一个非view类进行动画操作。
  2. 属性动画可以做到真正的改变view对象的属性值。而补间动画只是改变了view的动画效果。

ValueAnimator与ObjectAnimator

ObjectAnimator是属性动画中最总要的执行类,ObjectAnimator可以操作某个对象的属性值,但是这个属性值必须要有get和set方法,同时也可以设置view的执行线路,通过插值器来控制。
举个简单的例子:

ObjectAnimator.ofFloat(view, "rotationY", 0.0F, 360.0F).setDuration(500).start();

其可操作的属性有x/y;scaleX/scaleY;rotationX/ rotationY;transitionX/ transitionY等。
上面的例子是修改view的单个属性值,同样也可以同时修改多个属性,下面介绍两种

  1. PropertyValuesHolder属性值持有者

    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);ObjectAnimator.ofPropertyValuesHolder( this, pvhLeft, pvhTop).
  2. 提供一个不存在的属性值

    ObjectAnimator anim = ObjectAnimator.ofFloat(view, "long", 1.0F, 0.0F).setDuration(500);anim.start();anim.UpdateListener(new AnimatorUpdateListener() {    @Override    public void onAnimationUpdate(ValueAnimator animation) {        float cVal = (Float) animation.getAnimatedValue();        view.setAlpha(cVal);        view.setScaleX(cVal);        view.setScaleY(cVal);    }});

上面提到的都是修改对象已有的setter和getter方法的属性值。那么如果对象没有为某个属性提供提供setter和getter方法呢,我们也可以做到修改这些属性值,下面提供两种实现方式:

  1. 通过valueAnimation来实现,这个下面会讲解。
  2. 通过自己写一个包装类来实现。然后为该属性提供setter和getter方法。

    class ViewWrapper{    private View mView;    public int getWidth(){        return mView.getLayoutParams().width;    }}

ValueAnimator包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。
属性动画的应用有两个步骤:
1、计算属性的值。2、根据属性值执行相应的动作。
ValueAnimator只是完成了第一步骤,而要完成第二步还要借助于ValueAnimator.onUpdateListener接口,在此方法中可以通过ValueAnimator对象的getAnimatedValue()函数可以得到当前的属性值。

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);animation.setDuration(1000);animation.addUpdateListener(new AnimatorUpdateListener  () {    @Override     public void onAnimationUpdate(ValueAnimator animation) {         Log.i("update", ((Float)animation.getAnimatedValue()).toString());         // 此处可以根据getAnimatedValue获取到的属性值改变view相关的属性从而执行某些动作     }});animation.setInterpolator(new CycleInterpolator(3));animation.start();

Time Interpolator插值器与TypeEvaluator估值器

Time interplator:定义了属性值变化的方式,如线性均匀改变,开始慢然后逐渐快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了TimeInterplator。Interplator继承自TimeInterplator,内部没有任何其他代码。

  1. AccelerateInterpolator 加速,开始时慢中间加速
  2. DecelerateInterpolator 减速,开始时快然后减速
  3. AccelerateDecelerateInterolator 先加速后减速,开始结束时慢,中间加速
  4. AnticipateInterpolator 反向 ,先向相反方向改变一段再加速播放
  5. AnticipateOvershootInterpolator 反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
  6. BounceInterpolator 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
  7. CycleIinterpolator 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
  8. LinearInterpolator 线性,线性均匀改变
  9. OvershottInterpolator 回弹,最后超出目的值然后缓慢改变到目的值
  10. TimeInterpolator 一个接口,允许你自定义interpolator,以上几个都是实现了这个接口

TypeEvaluator:根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,android提供了以下几个evalutor:

  1. IntEvaluator:属性的值类型为int。
  2. FloatEvaluator:属性的值类型为float。
  3. ArgbEvaluator:属性的值类型为十六进制颜色值。
  4. TypeEvaluator:一个接口,可以通过实现该接口自定义Evaluator。

当然我们也可以自己定义估值器,如下:

public class FloatEvaluator implements TypeEvaluator {     public Object evaluate(float fraction, Object startValue, Object endValue) {            float startFloat = ((Number) startValue).floatValue();            return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);     }}

实例
接下来我们要实现的就是如下的 效果图:
这里写图片描述
在本例的实现中我们的重点也是在ValueAnimator和ObjectAnimator中读者可以结合上述知识内容来消化本例的动画技术。附上代码:

package com.example.custom.animation;import java.util.ArrayList;import com.example.custom.R;import android.animation.Animator;import android.animation.AnimatorListenerAdapter;import android.animation.AnimatorSet;import android.animation.ArgbEvaluator;import android.animation.ObjectAnimator;import android.animation.ValueAnimator;import android.app.Activity;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.RadialGradient;import android.graphics.Shader;import android.graphics.drawable.ShapeDrawable;import android.graphics.drawable.shapes.OvalShape;import android.os.Bundle;import android.view.MotionEvent;import android.view.View;import android.view.animation.AccelerateInterpolator;import android.view.animation.DecelerateInterpolator;import android.widget.LinearLayout;public class BouncingBalls extends Activity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.bouncing_balls);        LinearLayout container = (LinearLayout) findViewById(R.id.container);        container.addView(new MyAnimationView(this));    }    public class MyAnimationView extends View {        private static final int RED = 0xffFF8080;        private static final int BLUE = 0xff8080FF;        public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();        AnimatorSet animation = null;        public MyAnimationView(Context context) {            super(context);            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();        }        @Override        public boolean onTouchEvent(MotionEvent event) {            if (event.getAction() != MotionEvent.ACTION_DOWN &&                    event.getAction() != MotionEvent.ACTION_MOVE) {                return false;            }            // 初始化一个跳跳球            ShapeHolder newBall = initBouncingBall(event.getX(), event.getY());            float startY = newBall.getY();            float endY = getHeight() - 50;            float h = (float)getHeight();            float eventY = event.getY();            int duration = (int)(500 * ((h - eventY)/h));            // 操作newBall的Y属性值            ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY);            bounceAnim.setDuration(duration);            bounceAnim.setInterpolator(new AccelerateInterpolator());            ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x", newBall.getX(),newBall.getX() - 25f);            squashAnim1.setDuration(duration/4);            squashAnim1.setRepeatCount(1);            squashAnim1.setRepeatMode(ValueAnimator.REVERSE);            squashAnim1.setInterpolator(new DecelerateInterpolator());            ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall, "width", newBall.getWidth(),newBall.getWidth() + 50);            squashAnim2.setDuration(duration/4);            squashAnim2.setRepeatCount(1);            squashAnim2.setRepeatMode(ValueAnimator.REVERSE);            squashAnim2.setInterpolator(new DecelerateInterpolator());            ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y", endY, endY + 25f);            stretchAnim1.setDuration(duration/4);            stretchAnim1.setRepeatCount(1);            stretchAnim1.setInterpolator(new DecelerateInterpolator());            stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);            ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall, "height",newBall.getHeight(), newBall.getHeight() - 25);            stretchAnim2.setDuration(duration/4);            stretchAnim2.setRepeatCount(1);            stretchAnim2.setInterpolator(new DecelerateInterpolator());            stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);            ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY, startY);            bounceBackAnim.setDuration(duration);            bounceBackAnim.setInterpolator(new DecelerateInterpolator());            AnimatorSet bouncer = new AnimatorSet();            bouncer.play(bounceAnim).before(squashAnim1);            bouncer.play(squashAnim1).with(squashAnim2);            bouncer.play(squashAnim1).with(stretchAnim1);            bouncer.play(squashAnim1).with(stretchAnim2);            bouncer.play(bounceBackAnim).after(stretchAnim2);            ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);            fadeAnim.setDuration(250);            fadeAnim.addListener(new AnimatorListenerAdapter() {                @Override                public void onAnimationEnd(Animator animation) {                    balls.remove(((ObjectAnimator)animation).getTarget());                }            });            AnimatorSet animatorSet = new AnimatorSet();            animatorSet.play(bouncer).before(fadeAnim);            animatorSet.start();            return true;        }        private ShapeHolder initBouncingBall(float x, float y) {            int red = (int)(Math.random() * 255);            int green = (int)(Math.random() * 255);            int blue = (int)(Math.random() * 255);            int color = 0xff000000 | red << 16 | green << 8 | blue;            int darkColor = 0xff000000 | red/4 << 16 | green/4 << 8 | blue/4;            // 实例化一个圆形            OvalShape circle = new OvalShape();            circle.resize(50f, 50f);            // 设置画笔的形状            ShapeDrawable drawable = new ShapeDrawable(circle);            Paint paint = drawable.getPaint();             // 第一个,第二个参数表示渐变圆中心坐标,半径,圆心颜色,圆边缘颜色,渲染器平铺模式            RadialGradient gradient = new RadialGradient(37.5f, 12.5f, 50f, color, darkColor, Shader.TileMode.CLAMP);            // 给画笔设置著色器            paint.setShader(gradient);            ShapeHolder shapeHolder = new ShapeHolder(drawable);            shapeHolder.setX(x - 25f);            shapeHolder.setY(y - 25f);            shapeHolder.setPaint(paint);            balls.add(shapeHolder);            return shapeHolder;        }        @Override        protected void onDraw(Canvas canvas) {            for (int i = 0; i < balls.size(); ++i) {                ShapeHolder shapeHolder = balls.get(i);                canvas.save();                canvas.translate(shapeHolder.getX(), shapeHolder.getY());                shapeHolder.getShape().draw(canvas);                canvas.restore();            }        }    }}
package com.example.custom.animation;import android.graphics.Paint;import android.graphics.RadialGradient;import android.graphics.drawable.ShapeDrawable;import android.graphics.drawable.shapes.Shape;import android.view.View;public class ShapeHolder {    private float x = 0, y = 0;    private int color;    private float alpha = 1f;    private Paint paint;    private ShapeDrawable shape;    private RadialGradient gradient;    public void setPaint(Paint value) {        paint = value;    }    public Paint getPaint() {        return paint;    }    public void setX(float value) {        x = value;    }    public float getX() {        return x;    }    public void setY(float value) {        y = value;    }    public float getY() {        return y;    }    public void setShape(ShapeDrawable value) {        shape = value;    }    public ShapeDrawable getShape() {        return shape;    }    public int getColor() {        return color;    }    public void setColor(int value) {        shape.getPaint().setColor(value);        color = value;    }    public void setGradient(RadialGradient value) {        gradient = value;    }    public RadialGradient getGradient() {        return gradient;    }    public void setAlpha(float alpha) {        this.alpha = alpha;        shape.setAlpha((int)((alpha * 255f) + .5f));    }    public float getWidth() {        return shape.getShape().getWidth();    }    public void setWidth(float width) {        Shape s = shape.getShape();        s.resize(width, s.getHeight());    }    public float getHeight() {        return shape.getShape().getHeight();    }    public void setHeight(float height) {        Shape s = shape.getShape();        s.resize(s.getWidth(), height);    }    public ShapeHolder(ShapeDrawable s) {        shape = s;    }}
2楼adfghjkl昨天 20:41
可有代码上传?
1楼andywuchuanlong昨天 17:21
谢谢关注!所有的代码都在上面贴出来了得
  相关解决方案