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);//控制点坐标和终点坐标
三、
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); } });
解决问题。