自定义循环显示转换结果" java.lang.UnsupportedOperationException"什么时候暂停?

时间:2014-11-05 03:37:00

标签: android android-5.0-lollipop shared-element-transition activity-transition

我创建了一个自定义循环显示过渡,用作Activity的输入过渡的一部分(具体来说,我通过调用Window#setEnterTransition()将过渡设置为窗口的输入过渡):

public class CircularRevealTransition extends Visibility {
    private final Rect mStartBounds = new Rect();

    /**
     * Use the view's location as the circular reveal's starting position.
     */
    public CircularRevealTransition(View v) {
        int[] loc = new int[2];
        v.getLocationInWindow(loc);
        mStartBounds.set(loc[0], loc[1], loc[0] + v.getWidth(), loc[1] + v.getHeight());
    }

    @Override
    public Animator onAppear(ViewGroup sceneRoot, final View v, TransitionValues startValues, TransitionValues endValues) {
        if (endValues == null) {
            return null;
        }
        int halfWidth = v.getWidth() / 2;
        int halfHeight = v.getHeight() / 2;
        float startX = mStartBounds.left + mStartBounds.width() / 2 - halfWidth;
        float startY = mStartBounds.top + mStartBounds.height() / 2 - halfHeight;
        float endX = v.getTranslationX();
        float endY = v.getTranslationY();
        v.setTranslationX(startX);
        v.setTranslationY(startY);

        // Create a circular reveal animator to play behind a shared
        // element during the Activity Transition.
        Animator revealAnimator = ViewAnimationUtils.createCircularReveal(v, halfWidth, halfHeight, 0f,
                FloatMath.sqrt(halfWidth * halfHeight + halfHeight * halfHeight));
        revealAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                // Set the view's visibility to VISIBLE to prevent the
                // reveal from "blinking" at the end of the animation.
                v.setVisibility(View.VISIBLE);
            }
        });

        // Translate the circular reveal into place as it animates.
        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("translationX", startX, endX);
        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("translationY", startY, endY);
        Animator translationAnimator = ObjectAnimator.ofPropertyValuesHolder(v, pvhX, pvhY);

        AnimatorSet anim = new AnimatorSet();
        anim.setInterpolator(getInterpolator());
        anim.playTogether(revealAnimator, translationAnimator);
        return anim;
    }
}

这通常正常。但是,当我在转换过程中单击“后退按钮”时,我得到以下异常:

Process: com.adp.activity.transitions, PID: 13800
java.lang.UnsupportedOperationException
        at android.view.RenderNodeAnimator.pause(RenderNodeAnimator.java:251)
        at android.animation.AnimatorSet.pause(AnimatorSet.java:472)
        at android.transition.Transition.pause(Transition.java:1671)
        at android.transition.TransitionSet.pause(TransitionSet.java:483)
        at android.app.ActivityTransitionState.startExitBackTransition(ActivityTransitionState.java:269)
        at android.app.Activity.finishAfterTransition(Activity.java:4672)
        at com.adp.activity.transitions.DetailsActivity.finishAfterTransition(DetailsActivity.java:167)
        at android.app.Activity.onBackPressed(Activity.java:2480)

我收到此错误有什么具体原因吗?应该如何避免?

3 个答案:

答案 0 :(得分:10)

您需要创建Animator的子类,忽略对pause()resume()的调用,以避免此异常。

有关详细信息,我刚刚完成了有关此主题的帖子:

答案 1 :(得分:3)

  

我收到此错误有什么具体原因吗?

ViewAnimationUtils.createCircularReveal是创建新RevealAnimator的快捷方式,RenderNodeAnimator.pauseRenderNodeAnimator的子类。默认情况下,Activity.finishAfterTransition会抛出UnsupportedOperationException。您会在堆栈跟踪中看到这种情况:

java.lang.UnsupportedOperationException
        at android.view.RenderNodeAnimator.pause(RenderNodeAnimator.java:251)

在Lollipop中调用Activity.onBackPressed后,它会对Transition.pause(android.view.View)进行新的调用,最终会在EnterTransitionCoordinator handles the entering Transition once it's completed.中回拨Animator.pause,这时候就是{ {1}}终于被抛出了。

转换完成后使用“后退”按钮时未抛出的原因是TransitionListener

的原因
  

应该如何避免?

我想你有几个选择,但两者都不是很理想:

选项1

致电UnsupportedOperationException时附加ActivityTransitionState.clear,以便您可以监控何时调用“后退”按钮。所以,像:

Window.setEnterTransition

选项2

使用反射来调用ActivityTransitionState.startExitBackTransition,这将阻止在Here's a gfy of the results.中调用public class YourActivity extends Activity { /** True if the current window transition is animating, false otherwise */ private boolean mIsAnimating = true; @Override protected void onCreate(Bundle savedInstanceState) { // Get the Window and enable Activity transitions final Window window = getWindow(); window.requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); // Call through to super super.onCreate(savedInstanceState); setContentView(R.layout.activity_child); // Set the window transition and attach our listener final Transition circularReveal = new CircularRevealTransition(yourView); window.setEnterTransition(circularReveal.addListener(new TransitionListenerAdapter() { @Override public void onTransitionEnd(Transition transition) { super.onTransitionEnd(transition); mIsAnimating = false; } })); // Restore the transition state if available if (savedInstanceState != null) { mIsAnimating = savedInstanceState.getBoolean("key"); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // Save the current transition state outState.putBoolean("key", mIsAnimating); } @Override public void onBackPressed() { if (!mIsAnimating) { super.onBackPressed(); } } }

Transition.pause(android.view.View)

显然每个都有缺点。选项1基本上禁用“后退”按钮,直到转换完成。选项2允许您使用“后退”按钮进行中断,但会清除过渡状态并使用反射。

{{3}}你可以看到它是如何从“A”完全转换到“M”再返回,然后“后退”按钮会中断转换并返回“A”。如果你观看它会更有意义。

无论如何,我希望能帮到你一些。

答案 2 :(得分:0)

您可以添加侦听器以输入在方法transitionInProgress / onTransitionStart()中设置标记onTransitionEnd()的转换。然后,您可以覆盖方法finishAfterTransition(),然后检查transitionInProgress标记,并仅在转换完成时调用super。否则,您只能finish() Activity或无所事事。

override fun finishAfterTransition() {
    if (!transitionInProgress){
        super.finishAfterTransition()
    } else {
        finish()
    }
}