Результаты пользовательского кругового обнаружения в «java.lang.UnsupportedOperationException» при приостановке?

Я создал настраиваемый круговой показ, чтобы использовать его как часть перехода в действие 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) 

Есть ли какая-то конкретная причина, по которой я получаю эту ошибку? Как этого избежать?

Вам нужно будет создать подкласс Animator который игнорирует вызовы на pause() и resume() , чтобы избежать этого исключения.

Для получения дополнительной информации я только что закончил сообщение об этой теме ниже:

Есть ли какая-то конкретная причина, по которой я получаю эту ошибку?

ViewAnimationUtils.createCircularReveal – это ярлык для создания нового RevealAnimator , который является подклассом RenderNodeAnimator . По умолчанию RenderNodeAnimator.pause UnsupportedOperationException . Вы видите, что это происходит здесь в вашей трассе стека:

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

Когда Activity.onBackPressed вызывается в Lollipop, он вызывает новый вызов Activity.finishAfterTransition , который в конечном итоге делает обратный вызов в Animator.pause в Transition.pause(android.view.View) , который возникает, когда ваше UnsupportedOperationException окончательно выбрасывается.

Причина, по которой она не выбрасывается при использовании кнопки «Назад» после завершения перехода, объясняется тем, как EnterTransitionCoordinator обрабатывает EnterTransitionCoordinator Transition после его завершения.

Как этого избежать?

Я полагаю, у вас есть несколько вариантов, но ни один из них не идеален:

Опция 1

Прикрепите TransitionListener когда вы вызываете Window.setEnterTransition чтобы вы могли отслеживать, когда вызывать кнопку «Назад». Итак, что-то вроде:

 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(); } } } 

Вариант 2

Используйте отражение, чтобы вызвать ActivityTransitionState.clear , что остановит Transition.pause(android.view.View) на вызове в ActivityTransitionState.startExitBackTransition .

 @Override public void onBackPressed() { if (!mIsAnimating) { super.onBackPressed(); } else { clearTransitionState(); super.onBackPressed(); } } private void clearTransitionState() { try { // Get the ActivityTransitionState Field final Field atsf = Activity.class.getDeclaredField("mActivityTransitionState"); atsf.setAccessible(true); // Get the ActivityTransitionState final Object ats = atsf.get(this); // Invoke the ActivityTransitionState.clear Method final Method clear = ats.getClass().getDeclaredMethod("clear", (Class[]) null); clear.invoke(ats); } catch (final Exception ignored) { // Nothing to do } } 

Очевидно, что у каждого есть свои недостатки. Вариант 1 в основном отключает кнопку «назад» до завершения перехода. Вариант 2 позволяет вам прерывать использование кнопки «назад», но очищает состояние перехода и использует отражение.

Вот результат. Вы можете видеть, как он полностью переходит с «А» на «М» и обратно, затем кнопка «назад» прерывает переход и возвращается к «А». Это будет иметь больше смысла, если вы будете смотреть его.

Во всяком случае, я надеюсь, что это поможет вам.