工具类实现多View顺序播放动画偏移异常的原因及解决方案
问题原因分析
核心问题是多个View共享了同一个AnimationSet实例:
Android的Animation类是带状态的可变对象,启动偏移量、启动时间等属性都存在实例内部。你在调用工具类方法时只传入了一个AnimationSet实例,循环中每次修改startOffset都是覆盖同一个对象的属性,最终所有View的动画偏移量都被设置为最后一次计算的最大值,自然无法按顺序播放。
而你直接在Fragment中编写的逻辑每次循环都会调用getAnimationSet()生成全新的AnimationSet实例,每个View的动画状态完全独立,所以偏移量不会互相覆盖,运行符合预期。
修复方案
修改工具类逻辑,保证每个View都使用独立的动画实例即可,有两种常用实现方式:
方案1:利用Animation的Cloneable接口
Android系统的Animation类本身实现了Cloneable接口,可以直接拷贝已有动画的配置生成新实例:
public void applyAnimationToEachView(@NonNull Collection<View> views, @NonNull AnimationSet baseAnimationSet, long offset, boolean offsetSequentially) { int i = 0; for (View view: views) { try { // 每个View生成独立的动画副本 AnimationSet currentAnim = (AnimationSet) baseAnimationSet.clone(); view.setAnimation(currentAnim); if (offsetSequentially) { currentAnim.setStartOffset(offset * i); } else { currentAnim.setStartOffset(offset); } currentAnim.start(); i++; } catch (CloneNotSupportedException e) { // 理论上Animation实现了Cloneable,不会走到该分支 e.printStackTrace(); } } }
方案2:传入动画工厂(更推荐,无异常处理负担)
定义动画工厂接口,调用方传入实例生成逻辑,工具类每次循环都调用工厂生成新动画:
第一步:定义工厂接口
public interface AnimationFactory { AnimationSet createAnimation(); }
第二步:修改工具类方法
public void applyAnimationToEachView(@NonNull Collection<View> views, @NonNull AnimationFactory factory, long offset, boolean offsetSequentially) { int i = 0; for (View view: views) { AnimationSet currentAnim = factory.createAnimation(); view.setAnimation(currentAnim); if (offsetSequentially) { currentAnim.setStartOffset(offset * i); } else { currentAnim.setStartOffset(offset); } currentAnim.start(); i++; } }
第三步:Kotlin侧调用示例
override fun onHiddenChanged(hidden: Boolean) { if (!hidden) AnimationManager().applyAnimationToEachView( visibleCards as Collection<View>, // 传入动画生成逻辑,每次调用都返回新实例 { getAnimationSet() }, 100, true ) }
内容的提问来源于stack exchange,提问作者Corec
相关产品推荐
相关产品推荐

