You need to enable JavaScript to run this app. Android中如何让MyView绘制的六边形沿指定路径实现位移动画
优惠活动
大模型
产品
解决方案
定价
更多

Android中如何让MyView绘制的六边形沿指定路径实现位移动画

核心问题定位

直接拆解你当前代码里导致动画不生效的硬伤:

  • 自定义的setStartX/setStartY仅做了变量赋值,完全没有触发View的重绘流程,就算动画系统改了x/y的值,页面也不会刷新
  • onDraw方法里绘制六边形的所有坐标,完全没有用到x/y这两个动态变量,哪怕x/y改对了,绘制位置也不会变
  • 自定义的getX()方法直接覆盖了View原生的同名方法,会导致整个视图的坐标计算混乱
  • 定义路径时多写了冗余的moveTo,把连续轨迹拆成了孤立的线段,动画路径不连贯
  • ObjectAnimator对自定义属性的匹配逻辑有前提要求,你现在的setter不满足触发条件
分步修改方案

1. 补全setter的重绘触发逻辑

View要刷新必须主动调用invalidate(),把原来的setter方法改成赋值后立刻请求重绘的形式:

public void setStartX(float ex) {
    x = ex;
    invalidate();
}
public void setStartY(float ey) {
    y = ey;
    invalidate();
}

注意:建议把自定义的x、y对应的属性名改成不冲突的名称,比如hexX、hexY,对应的setter/getter写成setHexX()、getHexX(),避免和View系统自带的getX()/setX()方法重名,从根源上避免坐标计算混乱。

2. 修正onDraw的坐标映射逻辑

你现在的六边形绘制逻辑是基于自身画布的相对坐标,必须在绘制前把画布平移到动态更新的x/y位置,才能让图形跟着坐标移动:

@Override
protected void onDraw(Canvas canvas) {
    Paint myBrush = this.getBrush();
    float comp = myBrush.getStrokeWidth()/2;
    float canWidth = getSize();
    float canHeight = getSize();

    // 保存当前画布状态,平移到动态坐标位置
    canvas.save();
    canvas.translate(x, y);

    // 你原来的六边形绘制代码不需要任何修改
    canvas.drawLine(canWidth/3, 0+comp, 2*canWidth/3, 0+comp, myBrush);
    canvas.drawLine(2*canWidth/3, 0+comp, canWidth-comp, canHeight/3, myBrush);
    canvas.drawLine(canWidth-comp, canHeight/3, canWidth-comp, 2*canHeight/3, myBrush);
    canvas.drawLine(canWidth-comp, 2*canHeight/3, 2*canWidth/3, canHeight-comp, myBrush);
    canvas.drawLine(2*canWidth/3, canHeight-comp, canWidth/3, canHeight-comp, myBrush);
    canvas.drawLine(canWidth/3, canHeight-comp, 0+comp, 2*canHeight/3, myBrush);
    canvas.drawLine(0+comp, 2*canHeight/3, 0+comp, canHeight/3, myBrush);
    canvas.drawLine(0+comp, canHeight/3, canWidth/3, 0+comp, myBrush);

    // 恢复画布状态,避免影响其他绘制逻辑
    canvas.restore();
}

3. 修正路径定义的冗余逻辑

你原来的路径写了两次moveTo,打断了连续的竖线轨迹,删掉多余的moveTo即可:

Path hexPath = new Path();
hexPath.moveTo(10, 10); // 仅在路径起点调用一次
hexPath.lineTo(10, PHONE_DIMS.y * 4/5); // 连续绘制到底部

4. 匹配ObjectAnimator的属性要求

ObjectAnimator.ofFloat(target, "属性1", "属性2", path)这个构造方法会自动插值算出路径上的每一个x、y值,传给对应的setter方法。如果按照之前的建议把属性名改成不冲突的hexX、hexY,对应的调用逻辑就是:

// 匹配setHexX、setHexY方法
ObjectAnimator hexAn = ObjectAnimator.ofFloat(hex, "hexX", "hexY", hexPath);
hexAn.setInterpolator(new OvershootInterpolator());
hexAn.setDuration(5000);
hexAn.start();

如果需要兼容Android 5.0以下的低版本,可以通过PropertyValuesHolder配合PathInterpolator实现同样效果,不需要额外重写复杂逻辑。

关键注意事项
  • 所有和动画绑定的自定义属性,setter方法必须在赋值后调用invalidate(),否则动画系统就算修改了属性值,视图也不会重绘,看起来就像动画完全没生效
  • 路径绘制时moveTo只需要在轨迹最开始调用一次,后续连续的轨迹点直接用lineTo连接即可,多余的moveTo会把路径拆成孤立的节点,导致动画跳变
  • 不要让自定义的方法和View系统内置方法重名,比如你现在的getX()完全覆盖了系统方法,会导致布局测量、触摸事件的坐标计算全部出错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 12:15:04