Android 贝塞尔 星球 星际 旋转动画

效果

Android 贝塞尔 星球 星际 旋转动画

三个星球,ABC。

当点击星球B ,则B星球逆时针旋转到A星球的位置,A星球旋转到C星球的位置,C星球旋转到B星球的位置。

如果点击的是C星球,则顺时针旋转。

 

此动画涉及到ObjectAnimator动画,贝塞尔曲线,路径path等技术点。

 

下面说说逻辑:

一、首先确定三个星球的坐标,分别A(aX, aY), B(bX, By), C(cX, cY)

二、了解贝塞尔曲线,可以网上查找。此功能只需 开始点、重点和控制点。

三、画路径path,调用moveTo(起始点坐标),quadTo(控制点坐标和重点坐标)。

四、使用ObjectAnimator.ofFloat去按照path路径移动。

 

上代码:

一、

cX = width / 4;
cY = height / 2 - 200;
bX = width * 3 / 4;
bY = height / 2 - 200;
aX = width / 2;
aY = height / 2 + 50;

二、

c2bPath = new Path();
c2bPath.moveTo(cX, cY);//起始点
c2bPath.quadTo(aX, height / 2 - 500, bX, bY);//控制点坐标和终点坐标

Android 贝塞尔 星球 星际 旋转动画

三、

ObjectAnimator c2b_mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, c2bPath);

 

 

在实际开发中,遇到了些困难,在Android4.4 系统中,ObjectAnimator.ofFloat没有参数带path的方法。

所以需要向下兼容。

通过以下几点解决问题:

一、ValueAnimator.ofObject() 替换  ObjectAnimator.ofFloat

二、自定义BezierEvaluator类 实现TypeEvaluator<PointF>接口,重写里面的evaluate方法,加入贝塞尔曲线算法:

/**
 * @param t
 * @param point0 初始点
 * @param point3 终点
 * @return
 */
@Override
public PointF evaluate(float t, PointF point0, PointF point3) {
    PointF point = new PointF();
    //贝塞尔曲线算法
    point.x = (int) ((1 - t) * (1 - t) * point0.x + 2 * t * (1 - t) * point1.x + t * t * point3.x);
    point.y = (int) ((1 - t) * (1 - t) * point0.y + 2 * t * (1 - t) * point1.y + t * t * point3.y);
    return point;
}

上代码:

PointF pointStart = new PointF(bX, bY);
PointF pointEnd = new PointF(aX, aY);
PointF point1 = new PointF(bX, aY);//控制点
BezierEvaluator evaluator = new BezierEvaluator(point1);
ValueAnimator bezier = ValueAnimator.ofObject(evaluator, pointStart, pointEnd);
bezier.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        PointF pointF = (PointF) animation.getAnimatedValue();
        view.setX(pointF.x);
        view.setY(pointF.y);
    }
});

解决问题。