Android 自定义View动画篇之进阶

来源:互联网 发布:猎户座飞船 火星 知乎 编辑:程序博客网 时间:2024/05/17 23:29

Android 自定义View动画篇之进阶

  • Android 自定义View动画篇之进阶
    • Interpolator
    • TypeEvaluator

上一篇学习了一下属性动画的基础使用方法,还遗留了几个要点,就是TypeEvaluator< T >TimeInterpolator 以及ofObject的使用。在这一篇就会涉及到。

1.Interpolator

看我们之前属性动画的基础知识里面,包括了起始终点、重复次数、时长等,只能制造简单的动画。只有通过变动动画的执行速率,才能产生丰富有趣的动画来。所以,这里Interpolator就是起到这样一个作用的。
Interpolator一般称为差值器。而TimeInterpolator是属性动画独有的接口,其下有很多的实现类,都是Android给我们封装好了的,可以直接拿来用。比如说,匀速LinearInterpolator , 加速AccelerateInterpolator,先加速后减速AccelerateDecelerateInterpolator 等等,而当我们没有设置时的默认差值器就是AccelerateDecelerateInterpolator
通过 查看TimeInterpolator接口源码,我们就知道了只需要先实现TimeInterpolator,实现getInterpolation方法即可。getInterpolation中的参数input就是从0到1匀速变化。那么我们就来自定义Interpolator吧。
我们也写个加速运动吧。灵机一动,自由落体就是加速运动啊,公式相信大家都知道吧,那就开始吧。

public class FailingInterpolator implements TimeInterpolator {    @Override    public float getInterpolation(float input) {        return input * input;    }}

估计大家以为会很复杂,结果呵呵,就一句话。但是这里没有用加速度10m/s²,为什么呢?如果想真的是自由落体,那么距离就和时间有关系了。限定了距离,时间就固定,限定了时间,距离也要重新计算,除非不想限定运行的距离。那这里加速度是多少呢,比较简单,自己看看。
给个自定义View的代码,以防有的人看不太懂。

public class FailingView extends View {    private static final float radius = 100;    private Bitmap mBitmap;    private int mWidth, mHeight;    private Point mPoint;    public FailingView(Context context) {        this(context, null);    }    public FailingView(Context context, AttributeSet attrs) {        super(context, attrs);        BitmapFactory.Options options = new BitmapFactory.Options();        options.inSampleSize = 4;        mBitmap = BitmapFactory.decodeResource(this.getResources(), R.mipmap.mana, options);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        mWidth = w;        mHeight = h;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if(mPoint == null) {            mPoint = new Point(mWidth/2, 0);            startAnimator();            drawBitmap(canvas);        }else {            drawBitmap(canvas);        }    }    private void drawBitmap(Canvas canvas) {        canvas.drawBitmap(mBitmap, mPoint.getX() - mBitmap.getWidth()/2, mPoint.getY(), null);    }    private void startAnimator() {        ValueAnimator mAnimator = ValueAnimator.ofFloat(0, mHeight);        mAnimator.setInterpolator(new FailingInterpolator());        mAnimator.setDuration(2000);        mAnimator.start();        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                mPoint.setY((Float) animation.getAnimatedValue());                invalidate();            }        });    }}

这里都是前面的知识点,只需要通过setInterpolator 设置我们的自定义Interpolater就行了。来看一下结果吧。

这里写图片描述

2.TypeEvaluator

TypeEvaluator就是设定从初始值变化到结束值的“姿势”,是躺着的过去的,还是跑着过去的。我们可以看一下TypeEvaluator的实现类FloatEvaluator,源码很简单,就是实现TypeEvaluator,然后重写其唯一的方法evaluate。evaluate方法中有三个参数,后面两个看名字就知其含义了,起始值和结束值,而最后一个fraction表示动画的完成度。其实上面自定义Interpolater的返回值就是它了。
刚才说了既然Interpolater的返回值就是fraction,那么就有一种特殊情况了,就是在getInterpolation方法中input不做变换。这样我们就可以做出和上面的例子一样的效果,同样是加速下落。考虑到在画bitmap时,需要限定绘画的位置,通过改变这个点,就能达到重复绘制bitmap,从而产生动画。所以我们需要先新建一个点的bean文件。

public class Point {    private float x;    private float y;    public Point() {    }    public Point(float x, float y) {        this.x = x;        this.y = y;    }    public void setX(float x) {        this.x = x;    }    public float getX() {        return x;    }    public void setY(float y) {        this.y = y;    }    public float getY() {        return y;    }}

接下来才是写我们的自定义TypeEvaluator了。

public class FailingEvaluator implements TypeEvaluator {    @Override    public Object evaluate(float fraction, Object startValue, Object endValue) {        Point mPoint;        Point startPoint = (Point) startValue;        Point endPoint = (Point) endValue;        mPoint = new Point(0, startPoint.getY() + endPoint.getY() * fraction * fraction);        return mPoint;    }}

详细的代码就不贴了,相信应该都会写了,来看下效果,应该和上面的一样的。忘记说了ofObject的用法,这里就用到了ValueAnimator的ofObject方法,而ObjectAnimator的ofObject方法的用法差不多,就不单独给示例了。

ValueAnimator mAnimator = ValueAnimator.ofObject(new FailingEvaluator(), new Point(0, 0), new Point(0, mHeight));

这里写图片描述

了解了原理之后,就来个稍微难一点的例子吧。既然是从初始值到结束值的一个过程,那么能否规定它运动的轨迹呢?就考虑到了使用前面绘图篇的相关知识了path等。这里给出的例子,同样是控制绘图点,达到圆形运动的效果。来看下代码。

public class PathEvaluator implements TypeEvaluator {    private static final float radius = 100;    private float[] pos;    private Point result;    @Override    public Object evaluate(float fraction, Object startValue, Object endValue) {        Point startPoint = (Point) startValue;        Point endPoint = (Point) endValue;        Path mPath = new Path();        pos = new float[2];        result = new Point(0, 0);        if(startPoint.getX() == endPoint.getX() && startPoint.getY() == endPoint.getY()) {            RectF rectF = new RectF(startPoint.getX() - 2 * radius, startPoint.getY() - radius,                    startPoint.getX(), startPoint.getY() + radius);            mPath.addArc(rectF, 0, 359.9f);            PathMeasure pathMeasure = new PathMeasure(mPath, false);            pathMeasure.getPosTan(pathMeasure.getLength() * fraction, pos, null);            result.setX(pos[0]);            result.setY(pos[1]);        }        return result;    }}

如果学习了前面的绘图篇,这个显然就不难了。来看下效果。

这里写图片描述

中间是卡了下,不要介意,懒的录了。。。

这些天都没写博客,感觉有点松懈了。就当休息了吧,这段时间要加油了。上一篇说要写个综合的例子,其实是我想了好久都没写成功,然后强迫症犯了,一直没更新。额,下一篇应该会比较快,先立个flag吧。

PS:本人水平实在有限,如有错误之处,还望不吝赐教!


参考:
Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法
Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法

0 0