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

如何在Android Canvas.drawCircle()实现圆形脉冲动画(基于可缩放平移Bitmap)

嘿,我来帮你搞定这个Canvas圆形脉冲动画的问题!因为你是直接在可缩放平移的Bitmap地图上绘制,没法依赖常规View体系的动画框架,咱们换个思路——用逐帧更新状态+定时重绘的方式来实现,具体步骤如下:

实现Canvas圆形脉冲动画的方案

1. 先定义动画状态变量

在负责地图绘制的类里(比如自定义View或者你的绘图逻辑类),添加几个变量来跟踪脉冲的状态:

// 脉冲动画核心变量
private long lastAnimTime = 0;
private float pulseBaseRadius = 30f; // 圆形基础半径
private float currentPulseRadius = 30f; // 当前脉冲半径
private float currentAlpha = 1f; // 当前透明度
private static final float MAX_PULSE_RADIUS = 60f; // 脉冲扩散的最大半径
private static final long PULSE_DURATION = 1000; // 一个脉冲周期(毫秒)

2. 编写动画状态更新逻辑

每次绘制前,计算当前动画的进度,动态更新半径和透明度:

private void updatePulseState() {
    long now = System.currentTimeMillis();
    if (lastAnimTime == 0) {
        lastAnimTime = now;
        return;
    }
    // 计算当前周期内的进度(0~1之间循环)
    float progress = ((now - lastAnimTime) % PULSE_DURATION) / (float) PULSE_DURATION;
    // 半径从基础值向外扩散到最大值,同时透明度从完全不透明降到完全透明
    currentPulseRadius = pulseBaseRadius + (MAX_PULSE_RADIUS - pulseBaseRadius) * progress;
    currentAlpha = 1f - progress;
}

3. 修改你的绘制代码

把原来的固定半径绘制改成动态的,并且每次绘制完触发重绘来维持动画:

Paint pCirclePink = new Paint();
pCirclePink.setColor(Color.parseColor("#ff0000"));
pCirclePink.setAntiAlias(true);

if (userPlaceBeacon != null) {
    // 先更新动画状态
    updatePulseState();
    
    float centerX = (float) userPlaceBeacon.getPlacement_x() + offsetX;
    float centerY = (float) userPlaceBeacon.getPlacement_y() + offsetY;
    
    // 设置脉冲圆的透明度
    pCirclePink.setAlpha((int) (currentAlpha * 255));
    // 绘制动态变化的脉冲圆
    c.drawCircle(centerX, centerY, currentPulseRadius, pCirclePink);
    
    // 绘制固定的用户标记(这个不用动)
    Bitmap bmpUserDestination = ((BitmapDrawable) drawableUserMarker).getBitmap();
    bmpUserDestination = Bitmap.createScaledBitmap(bmpUserDestination, 28, 28, false);
    c.drawBitmap(bmpUserDestination, centerX - 14, centerY - 14, null);
    
    // 触发下一次重绘,让动画持续运行
    // 如果是在自定义View里,调用invalidate();如果是其他类,要通知地图视图执行重绘
    invalidate();
}
c.save();

4. 适配地图的缩放平移

因为你的地图支持缩放和平移,要确保脉冲圆的大小能跟着地图缩放同步变化。假设你有一个mapScaleFactor变量记录当前地图的缩放比例,修改半径计算逻辑:

// 让脉冲半径乘以缩放因子,保证缩放后脉冲大小比例一致
currentPulseRadius = (pulseBaseRadius + (MAX_PULSE_RADIUS - pulseBaseRadius) * progress) * mapScaleFactor;

额外优化小技巧

  • 如果想要更有层次感的脉冲效果,可以添加2-3组半径和透明度变量,每组的进度差开0.3左右(比如第一组用progress,第二组用(progress + 0.3f) % 1),这样就能实现多个圆依次扩散的效果。
  • 要是觉得手动计算进度麻烦,也可以用ValueAnimator来驱动半径和透明度变化,但手动计算的方式更灵活,不依赖View的生命周期,适配你这种直接操作Bitmap的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:19:44