You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android:如何实现View沿倒U型圆弧路径从(x1,y1)移动到(x2,y2)的动画

实现View沿倒U型圆弧路径的跳跃移动动画

核心思路

倒U型跳跃本质是让View沿上凸的圆弧轨迹移动,核心是先确定圆弧的几何参数(圆心、半径),再通过动画框架控制View沿轨迹逐帧更新位置。下面分两种常见实现方案,适合Android平台(基于Canvas、Path、动画API)。


方案一:Path + PathMeasure + ValueAnimator

通过Path构建倒U圆弧路径,用PathMeasure获取路径上的实时坐标,再通过ValueAnimator驱动View移动。

步骤&代码示例

  1. 定义基础参数(起点、终点、跳跃高度)
  2. 计算圆弧的圆心、半径(确保轨迹是上凸的倒U型)
  3. 构建圆弧路径
  4. 绑定动画并更新View位置
// 1. 基础参数定义
float startX = 100f, startY = 500f;
float endX = 500f, endY = 500f;
float jumpHeight = 150f; // 控制跳跃的高度

// 2. 计算圆弧几何参数
float midX = (startX + endX) / 2;
float midY = (startY + endY) / 2;
float halfHorizontalDist = Math.abs(endX - startX) / 2;
// 勾股定理计算圆心到中点的垂直距离(圆心在两点连线下方,保证上凸)
float verticalOffset = (float) Math.sqrt(jumpHeight * jumpHeight - halfHorizontalDist * halfHorizontalDist);
float centerX = midX;
float centerY = midY + verticalOffset;
float radius = jumpHeight;

// 3. 构建倒U型圆弧路径
Path jumpPath = new Path();
jumpPath.moveTo(startX, startY);
// arcTo参数:矩形边界(包含圆弧的最小矩形)、起始角度、扫过角度、是否连接到起点
// 180度为左方向,扫过-180度即逆时针画上半圆,形成倒U
jumpPath.arcTo(
    centerX - radius, centerY - radius,
    centerX + radius, centerY + radius,
    180, -180, false
);

// 4. 绑定动画
PathMeasure pathMeasure = new PathMeasure(jumpPath, false);
float pathTotalLength = pathMeasure.getLength();

ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(1200); // 动画时长,单位毫秒
animator.addUpdateListener(animation -> {
    float progress = (float) animation.getAnimatedValue();
    float[] currentPos = new float[2];
    // 获取当前进度对应的路径坐标
    pathMeasure.getPosTan(pathTotalLength * progress, currentPos, null);
    // 更新View位置(减去自身宽高的一半,让View中心对齐路径点)
    targetView.setX(currentPos[0] - targetView.getWidth() / 2);
    targetView.setY(currentPos[1] - targetView.getHeight() / 2);
});
animator.start();

方案二:自定义TypeEvaluator + ObjectAnimator

直接通过几何公式计算圆弧上的实时坐标,无需构建Path,性能更高效。

步骤&代码示例

  1. 计算圆弧参数(同方案一)
  2. 自定义TypeEvaluator,根据动画进度计算当前坐标
  3. 用ObjectAnimator绑定自定义属性驱动动画
// 1. 基础参数与圆弧计算(同方案一)
float startX = 100f, startY = 500f;
float endX = 500f, endY = 500f;
float jumpHeight = 150f;

float midX = (startX + endX) / 2;
float midY = (startY + endY) / 2;
float halfHorizontalDist = Math.abs(endX - startX) / 2;
float verticalOffset = (float) Math.sqrt(jumpHeight * jumpHeight - halfHorizontalDist * halfHorizontalDist);
float centerX = midX;
float centerY = midY + verticalOffset;
float radius = jumpHeight;

// 计算起始角度与总角度差(确保轨迹方向正确)
float startAngle = (float) Math.toDegrees(Math.atan2(startY - centerY, startX - centerX));
float totalAngle = (float) Math.toDegrees(Math.atan2(endY - centerY, endX - centerX)) - startAngle;
if (totalAngle > 0) totalAngle -= 360; // 修正为逆时针方向的角度差

// 2. 自定义Evaluator,根据进度计算圆弧上的点
TypeEvaluator<PointF> arcEvaluator = (fraction, startPoint, endPoint) -> {
    float currentAngle = startAngle + totalAngle * fraction;
    double radian = Math.toRadians(currentAngle);
    float currentX = centerX + radius * (float) Math.cos(radian);
    float currentY = centerY + radius * (float) Math.sin(radian);
    return new PointF(currentX, currentY);
};

// 3. 绑定动画:需要给View添加setPosition方法(或用自定义属性)
ObjectAnimator animator = ObjectAnimator.ofObject(
    targetView, "position", arcEvaluator,
    new PointF(startX, startY), new PointF(endX, endY)
);
animator.setDuration(1200);
animator.start();

// 给目标View添加setPosition方法(如果是自定义View可直接集成,否则用包装类)
public void setPosition(PointF pos) {
    setX(pos.x - getWidth() / 2);
    setY(pos.y - getHeight() / 2);
}

关键注意事项

  • 轨迹适配:如果起点和终点不在同一水平线,需重新计算圆心位置,保证圆弧始终向上凸(可通过调整verticalOffset的正负来控制凸向)。
  • View对齐:更新位置时记得减去View自身宽高的一半,避免View左上角对齐路径点导致的偏移。
  • 动画优化:如果是频繁触发的动画,优先用方案二(无Path构建开销);如果需要更复杂的轨迹(比如多段圆弧),方案一更灵活。

内容的提问来源于stack exchange,提问作者omkar_dharmesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 11:01:15