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
This commit is contained in:
Andrei Stingaceanu 2016-12-09 03:34:18 +00:00 committed by Travis Collins
parent 68a3946982
commit 24b2fc718a

View File

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