LottieAnimationView场景恢复-导致的底部按钮显示相同

记录一个遇到的问题

使用Lottie优雅的实现矢量动画,用起来妙啊,能够做到普通帧动画无法做到的功能,模仿的腾讯视频底部切换的动画.但是使用中发现了下图的问题.

Animation.gif

我在这里点了快速运行,导致本身四个不同的图片变成和最后一个图片一样的了.,其实旋转屏也可以复现!
然鹅,如果出现这个问题的时候是旋转屏,我会直接晓得是场景恢复导致的,但是我发现的时候是快速运行和崩溃的时候复现的,我没有联想到,所以我找了好久.

那么问题已经找到了就是场景恢复导致的,那就去定位问题吧.

lottie 源码版本

implementation 'com.airbnb.android:lottie:2.7.0'

既然大致知道是场景恢复引发的这个事件,那么就直接查LottieAnimationView的这两个方法

  • onSaveInstanceState
  • onRestoreInstanceState

看了一下LottieAnimationView果然重写了这两个方法
onSaveInstanceState,果然保存了动画的属性,o(╥﹏╥)o

  @Override protected Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();
    SavedState ss = new SavedState(superState);
    ss.animationName = animationName;
    ss.animationResId = animationResId;
    ss.progress = lottieDrawable.getProgress();
    ss.isAnimating = lottieDrawable.isAnimating();
    ss.imageAssetsFolder = lottieDrawable.getImageAssetsFolder();
    ss.repeatMode = lottieDrawable.getRepeatMode();
    ss.repeatCount = lottieDrawable.getRepeatCount();
    return ss;
  }

onRestoreInstanceState 恢复的时候把对应的动画属性恢复过来了

@Override protected void onRestoreInstanceState(Parcelable state) {
    if (!(state instanceof SavedState)) {
      super.onRestoreInstanceState(state);
      return;
    }

    SavedState ss = (SavedState) state;
    super.onRestoreInstanceState(ss.getSuperState());
    animationName = ss.animationName;
    if (!TextUtils.isEmpty(animationName)) {
      setAnimation(animationName);
    }
    animationResId = ss.animationResId;
    if (animationResId != 0) {
      setAnimation(animationResId);
    }
    setProgress(ss.progress);
    if (ss.isAnimating) {
      playAnimation();
    }
    lottieDrawable.setImagesAssetsFolder(ss.imageAssetsFolder);
    setRepeatMode(ss.repeatMode);
    setRepeatCount(ss.repeatCount);
  }

你会说没毛病呀,一个对象一个资源,不会导致4个对象使用一个资源呀!这里先把原因说出来.
这四个LottieAnimationView有相同的id.
给你看个布局 R.layout.view_maintab,



    

//...省略

public class MainTab extends FrameLayout {
    public MainTab(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

       LayoutInflater.from(context).inflate(R.layout.view_maintab,
                this);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MainTab);
        String titleContent = typedArray.getString(R.styleable.MainTab_text);
        Drawable drawable = typedArray.getDrawable(R.styleable.MainTab_img_res);
        typedArray.recycle();

自定义了一个FrameLayout用来装布局,然后写一些共同的属性,来实现切换的tab!
问题原因:
这里因为场景恢复的数据通过onSaveInstanceState()先存到一个SparseArray container集合里,通过dispatchRestoreInstanceState()通过id来取出对应的数据.

   protected void dispatchRestoreInstanceState(SparseArray container) {
        if (mID != NO_ID) {
            //注意看这里
            Parcelable state = container.get(mID);
            if (state != null) {
                mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
                onRestoreInstanceState(state);
             //....
            }
        }
    }

在执行onSaveInstanceState()的时候最后一个tab因为id和前面的三个一致,直接覆盖了前面的数据.这就是问题的原因,那怎么办呢?

解决方式:
不写id了就好了呗!那你怎么获取对象呢?可以使用getChild()....等方式拿到对象.

此处应有签名

你可能感兴趣的:(LottieAnimationView场景恢复-导致的底部按钮显示相同)