Android ObjectAnimato отменяется до конца

У меня есть фрагмент с 3 LinearLayout внутри. По умолчанию у первого атрибут веса равен 1.

Каждый LinearLayout имеет OnClickListener, который запускает 2 анимации:

  • Анимация с весом от 0 до 1 для той, на которую нажали.
  • Анимация с весом от 1 до 0 для открытой в данный момент.

Моя проблема в том, что иногда анимация не заканчивается полностью.

Вот код, запускаемый OnClickListener:

private void launchAnimation(final LinearLayout llToExpand) {
    ViewWeightAnimationWrapper animationWrapper = new ViewWeightAnimationWrapper(llToExpand);
    ObjectAnimator anim = ObjectAnimator.ofFloat(animationWrapper,
            "weight",
            animationWrapper.getWeight(),
            1f);
    anim.setDuration(1000);

    anim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            Log.d("Anim1", "onAnimationEnd: Anim1 have ended");
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            Log.d("Anim1", "onAnimationCancel: Anim1 have been canceled.");
        }
    });

    ViewWeightAnimationWrapper animationWrapper2 = new ViewWeightAnimationWrapper(mLlCurrentlyOpened);
    ObjectAnimator anim2 = ObjectAnimator.ofFloat(animationWrapper2,
            "weight",
            animationWrapper2.getWeight(),
            0f);
    anim2.setDuration(1000);

    anim2.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            Log.d("Anim2", "onAnimationEnd: Anim2 have ended");
            mLlCurrentlyOpened = llToExpand;
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            Log.d("Anim2", "onAnimationCancel: Anim2 have been canceled.");
        }
    });
    anim.start();
    anim2.start();
}

Вот код моего ViewWeightAnimationWrapper:

public class ViewWeightAnimationWrapper {
private View view;

public ViewWeightAnimationWrapper(View view) {
    if (view.getLayoutParams() instanceof LinearLayout.LayoutParams) {
        this.view = view;
    } else {
        throw new IllegalArgumentException("The view should be a LinearLayout");
    }
}

public void setWeight(float weight) {
    Log.i(String.valueOf(view.getId()), "setWeight: " + weight);
    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
    params.weight = weight;
    view.requestLayout();
}

public float getWeight() {
    return ((LinearLayout.LayoutParams) view.getLayoutParams()).weight;
}

Вот лог, который у меня есть, когда анимация не доходит до конца:

I/2131755212: setWeight: 0.5
I/2131755207: setWeight: 0.5
I/2131755212: setWeight: 0.5251222
I/2131755207: setWeight: 0.47487777
I/2131755212: setWeight: 0.55174345
I/2131755207: setWeight: 0.44825655
D/Anim1: onAnimationCancel: Anim1 have been canceled.
D/Anim1: onAnimationEnd: Anim1 have ended
D/Anim2: onAnimationCancel: Anim2 have been canceled.
D/Anim2: onAnimationEnd: Anim2 have ended

Я понятия не имею, почему моя анимация не отменяется каждый раз.

Как я могу узнать, что отменяет мои анимации? Можно ли принудительно завершить анимацию при ее отмене?


person Joffrey Lgt    schedule 16.05.2017    source источник


Ответы (2)


Я не нашел причину, почему анимация отменена. В документации говорится, что анимация отменяется, когда одна и та же анимация запускается для одного и того же объекта, что не было в моем случае.

Однако я нашел обходной путь здесь, который дает ожидаемый результат.

Я заменил ObjectAnimator пользовательской анимацией:

     /**
     * Launch the expand animation on the LinearLayout in parameter and launch the folding animation
     * on the currently opened LinearLayout.
     * @param llToExpand LinearLayout that we want to expand.
     */
    private void launchAnimation(final LinearLayout llToExpand) {

        // Create the and assign the animations
        ExpandAnimation expand = new ExpandAnimation(llToExpand, 0, 1);
        expand.setDuration(500);
        ExpandAnimation fold = new ExpandAnimation(mLlCurrentlyOpened, 1, 0);
        fold.setDuration(500);

        // Start the animations
        llToExpand.startAnimation(expand);
        mLlCurrentlyOpened.startAnimation(fold);

        // Switch the currently opened LinearLayout for the next time
        mLlCurrentlyOpened = llToExpand;
    }

Вот моя ExpandAnimation:

public class ExpandAnimation extends Animation {

private float mStartWeight;
private final float mEndWeight;
private final LinearLayout mContent;

public ExpandAnimation(LinearLayout content, float startWeight,
                float endWeight) {
    mStartWeight = startWeight;
    mEndWeight = endWeight;
    mContent = content;
}

@Override
protected void applyTransformation(float interpolatedTime,
                                   Transformation t) {
    LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContent
            .getLayoutParams();
    mStartWeight = lp.weight;
    lp.weight = (mStartWeight + ((mEndWeight - mStartWeight) * interpolatedTime));
    mContent.setLayoutParams(lp);
}

@Override
public boolean willChangeBounds() {
    return true;
}
}
person Joffrey Lgt    schedule 17.05.2017

Я просто столкнулся с тем, что может быть той же проблемой. Глядя на источник ObjectAnimator, он содержит WeakReference для цели анимации. В моем случае я использовал выделенный объект, созданный только для выполнения анимации, и оказалось, что слабая ссылка была единственной ссылкой. Таким образом, во время анимации он иногда разыменовывался. ObjectAnimator обрабатывает это «чисто», просто отменяя анимацию.

person tliebeck    schedule 22.12.2018