
libgdx 的 `progressbar` 默认不支持直接暂停动画;本文提供两种可靠方案:一是完全绕过内置动画,手动控制值更新并结合 `pause()`/`resume()` 生命周期回调实现精准暂停;二是条件性调用 `stage.act()` 以冻结动画逻辑。
在 LibGDX 中,ProgressBar 的 setAnimateDuration() 仅控制 knob(滑块)的缓动过渡时长,并非独立动画线程——其实际更新依赖于 Stage.act(deltaTime) 的持续调用。因此,无法通过简单标志位“暂停”内置动画,而需从框架生命周期或渲染逻辑层面干预。
✅ 推荐方案一:禁用动画 + 手动值更新(推荐)
这是最可控、最符合游戏逻辑的方式。核心思路是:
- 创建 ProgressBar 时传入 false 作为 animate 参数(即 new ProgressBar(min, max, step, false, style));
- 在 render() 中根据 active 状态决定是否更新 setValue();
- 利用 LibGDX 应用生命周期回调 pause() 和 resume() 切换状态。
以下为精简可运行示例(适配现代 LibGDX 项目结构,如使用 ApplicationAdapter):
public class ProgressBarDemo extends ApplicationAdapter {
private SpriteBatch batch;
private Stage stage;
private ProgressBar bar;
private boolean isActive = true;
private float maxValue = 25f; // 与动画时长语义对齐,便于理解
@Override
public void create() {
batch = new SpriteBatch();
stage = new Stage(new FitViewport(800, 600));
// 构建样式(同原问题,已优化资源释放)
ProgressBarStyle style = buildProgressBarStyle();
bar = new ProgressBar(0f, maxValue, 0.1f, false, style); // ⚠️ animate = false
bar.setBounds(100, 300, 600, 40);
stage.addActor(bar);
}
private ProgressBarStyle buildProgressBarStyle() {
ProgressBarStyle style = new ProgressBarStyle();
// 背景(Cyan)
Pixmap bg = new Pixmap(100, 40, Pixmap.Format.RGBA8888);
bg.setColor(Color.CYAN);
bg.fill();
style.background = new TextureRegionDrawable(new TextureRegion(new Texture(bg)));
bg.dispose();
// Knob(Red,当前值指示器)
Pixmap knob = new Pixmap(10, 40, Pixmap.Format.RGBA8888);
knob.setColor(Color.RED);
knob.fill();
style.knob = new TextureRegionDrawable(new TextureRegion(new Texture(knob)));
knob.dispose();
// knobBefore(可选:已填充部分颜色,此处与 knob 一致)
style.knobBefore = style.knob;
return style;
}
@Override
public void render() {
// ✅ 关键:仅在激活状态下更新进度
if (isActive && bar.getValue() < maxValue) {
float delta = Gdx.graphics.getDeltaTime();
bar.setValue(Math.min(bar.getValue() + delta, maxValue));
if (bar.getValue() >= maxValue - 0.01f) {
Gdx.app.log("ProgressBar", "Completed!");
}
}
stage.act(Gdx.graphics.getDeltaTime()); // 保持 UI 交互响应(按钮等仍可用)
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
stage.draw();
batch.end();
}
// ? LibGDX 生命周期回调:自动触发(无需手动注册)
@Override
public void pause() {
isActive = false;
Gdx.app.log("Lifecycle", "Progress paused.");
}
@Override
public void resume() {
isActive = true;
Gdx.app.log("Lifecycle", "Progress resumed.");
}
@Override
public void dispose() {
batch.dispose();
stage.dispose();
// 注意:此处应额外 dispose 所有 Texture 对象(示例中未显式保存,生产环境需管理)
}
}? 关键说明:bar.setValue() 是线程安全的,可在 render() 中安全调用;stage.act() 仍需调用,否则按钮点击等交互将失效 —— 暂停的是进度更新,不是整个 UI;maxValue = 25f 与原 setAnimateDuration(25) 语义对齐(单位:秒),便于调试和同步逻辑。
⚠️ 方案二:保留动画但冻结 stage.act()(慎用)
若坚持使用 animate = true,可通过跳过 stage.act() 来“冻结”所有动画及交互:
@Override
public void render() {
if (isActive) {
stage.act(Gdx.graphics.getDeltaTime()); // ✅ 更新动画 & 交互
} else {
// ❌ 不调用 act() → knob 缓动停止,按钮不可点
}
// ... draw ...
}⚠️ 风险提示:此方式会同时冻结所有 Actor 的 act() 行为(如按钮悬停、文本框光标、自定义动画等),不推荐用于含交互的 UI 场景。
✅ 最佳实践总结
| 场景 | 推荐做法 |
|---|---|
| 简单计时/加载条,需精确暂停/恢复 | ✅ 方案一(手动 setValue + 生命周期回调) |
| 进度与游戏逻辑强耦合(如技能冷却) | ✅ 方案一 + 自定义计时器(elapsedTime) |
| 必须保留 knob 缓动效果且无其他交互 | ⚠️ 方案二(仅限极简 UI) |
| 多个进度条需独立控制 | ✅ 将 isActive 改为每个 ProgressBar 的成员变量 |
最后提醒:所有 Texture 和 Pixmap 必须显式 dispose()(示例中已体现),避免内存泄漏;生产代码建议使用 AssetManager 统一管理资源。










