如何为Sceneform节点实现alpha透明度过渡动画?
问题根源
ObjectAnimator 正常运行的核心前提是目标对象存在与属性名匹配的公共setter方法。你之前实现的左右位移动画能正常工作,是因为Sceneform的Node类原生提供了位置属性的标准set/get接口;但Node本身没有直接暴露setAlpha()方法,直接传入属性名"alpha"时,ObjectAnimator找不到对应的属性赋值入口,动画完全不会触发。
另外哪怕你找到Node里隐藏的alpha相关字段,不调整材质的混合模式,透明度修改也不会正常显示——Sceneform默认材质是不透明渲染队列,会跳过透明度混合计算。
正确实现方法
前置配置(所有方案都需要先完成)
不管用哪种方式做alpha动画,首先要给节点对应材质开启透明混合,否则改透明度没有视觉效果:
Renderable targetRenderable = modelInnerNode2.getRenderable(); Material targetMat = targetRenderable.getMaterial(); // 把材质切换到透明渲染队列 targetMat.setInt(MaterialFactory.MATERIAL_BLEND_MODE, BlendMode.TRANSLUCENT.value); // 初始化alpha为完全不透明 targetMat.setFloat(MaterialFactory.MATERIAL_ALPHA, 1f);
如果节点绑定的Renderable包含多个子材质,要遍历所有材质逐一设置上述两个参数,否则会出现部分模型不透明的问题。
方案1:包装类适配原有ObjectAnimator逻辑
如果你想保留之前写ObjectAnimator的代码习惯,只需要写一个简单的包装类,给alpha属性提供标准set/get方法,内部把值同步给材质即可:
public class NodeAlphaController { private final Material bindMaterial; private float currentAlpha = 1f; public NodeAlphaController(Node targetNode) { this.bindMaterial = targetNode.getRenderable().getMaterial(); } // 给ObjectAnimator提供alpha的setter public void setAlpha(float alpha) { this.currentAlpha = alpha; bindMaterial.setFloat(MaterialFactory.MATERIAL_ALPHA, alpha); } // 给ObjectAnimator提供alpha的getter public float getAlpha() { return currentAlpha; } }
之后用这个包装类初始化动画,你之前写的动画参数可以完全保留,直接运行即可:
NodeAlphaController alphaController = new NodeAlphaController(modelInnerNode2); ObjectAnimator anim = ObjectAnimator.ofFloat(alphaController, "alpha", 1f, 0f); anim.setDuration(1000); anim.setInterpolator(new AccelerateInterpolator()); anim.setAutoCancel(true); anim.setRepeatCount(ObjectAnimator.INFINITE); anim.setRepeatMode(ObjectAnimator.RESTART); anim.start();
方案2:帧回调手动实现动画
如果不想额外写包装类,可以直接用Sceneform提供的每帧更新回调,自己计算alpha值更新,逻辑更可控:
// 先完成前面说的材质透明配置 modelInnerNode2.getScene().addOnUpdateListener(frameTime -> { // 按1秒周期计算当前alpha值,实现1到0的循环淡出 long cycleTime = System.currentTimeMillis() % 1000; float currentAlpha = 1f - (cycleTime / 1000f); targetMat.setFloat(MaterialFactory.MATERIAL_ALPHA, currentAlpha); });
如果需要做非线性动画,只需要把计算出来的进度值套上你需要的插值器逻辑即可。
避坑提示
- 不要通过缩放节点、修改节点可见性的方式伪造透明效果,会导致节点碰撞体、子节点坐标同步异常
- 如果使用了自定义材质,要确保材质shader中声明了
MATERIAL_ALPHA和MATERIAL_BLEND_MODE参数,否则参数设置不会生效 - 动画不需要时要及时移除回调或者cancel动画,避免内存泄漏
内容的提问来源于stack exchange,提问作者Manu Chandran
相关产品推荐
相关产品推荐

