From 24b2fc718abea42e67c11eeae2f20588c8bbd786 Mon Sep 17 00:00:00 2001 From: Andrei Stingaceanu Date: Fri, 9 Dec 2016 03:34:18 +0000 Subject: [PATCH] Support design - fix FAB elevation in API 21 The animations are really broken here. A hacky fix has been added in the past for versions 22-24 and now for version 21 just by bluntly set the elevation and translationZ by respecting the logic in the animations for 22-24. Bug: 33126409 Test: identified this bug from an existing test. Change-Id: I0cba73cda030ef7a66ffad452bc0f14b7687fc52 GitOrigin-RevId=829c95c8a3fd508b798bedff028d7d6b55e16ce5 PiperOrigin-RevId: 141514172 --- .../widget/FloatingActionButtonLollipop.java | 91 +++++++++++-------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/lib/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java b/lib/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java index d045586eb..24ef31441 100644 --- a/lib/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java +++ b/lib/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java @@ -28,6 +28,7 @@ import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.InsetDrawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.RippleDrawable; +import android.os.Build; import android.support.annotation.RequiresApi; import android.support.v4.graphics.drawable.DrawableCompat; import android.view.View; @@ -81,48 +82,64 @@ class FloatingActionButtonLollipop extends FloatingActionButtonIcs { @Override void onElevationsChanged(final float elevation, final float pressedTranslationZ) { - final StateListAnimator stateListAnimator = new StateListAnimator(); + final int sdk = Build.VERSION.SDK_INT; + if (sdk == 21) { + // Animations produce NPE in version 21. Bluntly set the values instead (matching the + // logic in the animations below). + if (mView.isEnabled()) { + mView.setElevation(elevation); + if (mView.isFocused() || mView.isPressed()) { + mView.setTranslationZ(pressedTranslationZ); + } else { + mView.setTranslationZ(0); + } + } else { + mView.setElevation(0); + mView.setTranslationZ(0); + } + } else { + final StateListAnimator stateListAnimator = new StateListAnimator(); - // Animate elevation and translationZ to our values when pressed - AnimatorSet set = new AnimatorSet(); - set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0)) - .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ) - .setDuration(PRESSED_ANIM_DURATION)); - set.setInterpolator(ANIM_INTERPOLATOR); - stateListAnimator.addState(PRESSED_ENABLED_STATE_SET, set); + // Animate elevation and translationZ to our values when pressed + AnimatorSet set = new AnimatorSet(); + set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0)) + .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ) + .setDuration(PRESSED_ANIM_DURATION)); + set.setInterpolator(ANIM_INTERPOLATOR); + stateListAnimator.addState(PRESSED_ENABLED_STATE_SET, set); - // Same deal for when we're focused - set = new AnimatorSet(); - set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0)) - .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ) - .setDuration(PRESSED_ANIM_DURATION)); - set.setInterpolator(ANIM_INTERPOLATOR); - stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET, set); + // Same deal for when we're focused + set = new AnimatorSet(); + set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0)) + .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ) + .setDuration(PRESSED_ANIM_DURATION)); + set.setInterpolator(ANIM_INTERPOLATOR); + stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET, set); - // Animate translationZ to 0 if not pressed - set = new AnimatorSet(); - set.playSequentially( - ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0), - // This is a no-op animation which exists here only for introducing the duration - // because setting the delay (on the next animation) via "setDelay" or "after" can - // trigger a NPE between android versions 21 and 24 (due to a framework bug). The - // issue has been fixed in version 25. - ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, mView.getTranslationZ()) - .setDuration(PRESSED_ANIM_DELAY), - ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f) - .setDuration(PRESSED_ANIM_DURATION)); + // Animate translationZ to 0 if not pressed + set = new AnimatorSet(); + set.playSequentially( + ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0), + // This is a no-op animation which exists here only for introducing the duration + // because setting the delay (on the next animation) via "setDelay" or "after" + // can trigger a NPE between android versions 22 and 24 (due to a framework + // bug). The issue has been fixed in version 25. + ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, mView.getTranslationZ()) + .setDuration(PRESSED_ANIM_DELAY), + ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f) + .setDuration(PRESSED_ANIM_DURATION)); + set.setInterpolator(ANIM_INTERPOLATOR); + stateListAnimator.addState(ENABLED_STATE_SET, set); - set.setInterpolator(ANIM_INTERPOLATOR); - stateListAnimator.addState(ENABLED_STATE_SET, set); + // Animate everything to 0 when disabled + set = new AnimatorSet(); + set.play(ObjectAnimator.ofFloat(mView, "elevation", 0f).setDuration(0)) + .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f).setDuration(0)); + set.setInterpolator(ANIM_INTERPOLATOR); + stateListAnimator.addState(EMPTY_STATE_SET, set); - // Animate everything to 0 when disabled - set = new AnimatorSet(); - set.play(ObjectAnimator.ofFloat(mView, "elevation", 0f).setDuration(0)) - .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f).setDuration(0)); - set.setInterpolator(ANIM_INTERPOLATOR); - stateListAnimator.addState(EMPTY_STATE_SET, set); - - mView.setStateListAnimator(stateListAnimator); + mView.setStateListAnimator(stateListAnimator); + } if (mShadowViewDelegate.isCompatPaddingEnabled()) { updatePadding();