Update FloatingActionButton's elevation handling
We now use a StateListAnimator for both the elevation
and translationZ handling. Matches the framework's button
impl more closely.
Also adds a disabled state which we didn't previously
handle.
Change-Id: I1c86d71495d75680d542a4fab7a1e87834ed572d
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index 189060a..329db1a 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -26,9 +26,14 @@
import android.support.annotation.Nullable;
import android.support.design.R;
import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
abstract class FloatingActionButtonImpl {
+ static final Interpolator ANIM_INTERPOLATOR = AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR;
+ static final long PRESSED_ANIM_DURATION = 100;
+ static final long PRESSED_ANIM_DELAY = 100;
+
Drawable mShapeDrawable;
Drawable mRippleDrawable;
CircularBorderDrawable mBorderDrawable;
@@ -48,6 +53,7 @@
android.R.attr.state_enabled};
static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused,
android.R.attr.state_enabled};
+ static final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled};
static final int[] EMPTY_STATE_SET = new int[0];
final VisibilityAwareImageButton mView;
@@ -74,7 +80,7 @@
final void setElevation(float elevation) {
if (mElevation != elevation) {
mElevation = elevation;
- onElevationChanged(elevation);
+ onElevationsChanged(elevation, mPressedTranslationZ);
}
}
@@ -83,13 +89,11 @@
final void setPressedTranslationZ(float translationZ) {
if (mPressedTranslationZ != translationZ) {
mPressedTranslationZ = translationZ;
- onTranslationZChanged(translationZ);
+ onElevationsChanged(mElevation, translationZ);
}
}
- abstract void onElevationChanged(float elevation);
-
- abstract void onTranslationZChanged(float translationZ);
+ abstract void onElevationsChanged(float elevation, float pressedTranslationZ);
abstract void onDrawableStateChanged(int[] state);
diff --git a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
index a6fa8d7..148aa32 100644
--- a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
+++ b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
@@ -33,7 +33,6 @@
class FloatingActionButtonGingerbread extends FloatingActionButtonImpl {
- private int mAnimationDuration;
private StateListAnimator mStateListAnimator;
private boolean mIsHiding;
@@ -43,8 +42,6 @@
ShadowViewDelegate shadowViewDelegate) {
super(view, shadowViewDelegate);
- mAnimationDuration = view.getResources().getInteger(android.R.integer.config_shortAnimTime);
-
mStateListAnimator = new StateListAnimator();
mStateListAnimator.setTarget(view);
@@ -54,8 +51,11 @@
mStateListAnimator.addState(FOCUSED_ENABLED_STATE_SET,
setupAnimation(new ElevateToTranslationZAnimation()));
// Reset back to elevation by default
- mStateListAnimator.addState(EMPTY_STATE_SET,
+ mStateListAnimator.addState(ENABLED_STATE_SET,
setupAnimation(new ResetElevationAnimation()));
+ // Set to 0 when disabled
+ mStateListAnimator.addState(EMPTY_STATE_SET,
+ setupAnimation(new DisabledElevationAnimation()));
}
@Override
@@ -128,7 +128,7 @@
}
@Override
- void onElevationChanged(float elevation) {
+ void onElevationsChanged(float elevation, float pressedTranslationZ) {
if (mShadowDrawable != null) {
mShadowDrawable.setShadowSize(elevation, elevation + mPressedTranslationZ);
updatePadding();
@@ -136,14 +136,6 @@
}
@Override
- void onTranslationZChanged(float translationZ) {
- if (mShadowDrawable != null) {
- mShadowDrawable.setMaxShadowSize(mElevation + translationZ);
- updatePadding();
- }
- }
-
- @Override
void onDrawableStateChanged(int[] state) {
mStateListAnimator.setState(state);
}
@@ -223,8 +215,8 @@
}
private Animation setupAnimation(Animation animation) {
- animation.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
- animation.setDuration(mAnimationDuration);
+ animation.setInterpolator(ANIM_INTERPOLATOR);
+ animation.setDuration(PRESSED_ANIM_DURATION);
return animation;
}
@@ -265,6 +257,13 @@
}
}
+ private class DisabledElevationAnimation extends BaseShadowAnimation {
+ @Override
+ protected float getTargetShadowSize() {
+ return 0f;
+ }
+ }
+
private static ColorStateList createColorStateList(int selectedColor) {
final int[][] states = new int[3][];
final int[] colors = new int[3];
diff --git a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
index 89d78b7..f41578b 100644
--- a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
+++ b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
@@ -17,6 +17,7 @@
package android.support.design.widget;
import android.animation.Animator;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.StateListAnimator;
import android.annotation.TargetApi;
@@ -29,23 +30,18 @@
import android.graphics.drawable.RippleDrawable;
import android.os.Build;
import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.ViewCompat;
+import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class FloatingActionButtonLollipop extends FloatingActionButtonIcs {
- private final Interpolator mInterpolator;
private InsetDrawable mInsetDrawable;
FloatingActionButtonLollipop(VisibilityAwareImageButton view,
ShadowViewDelegate shadowViewDelegate) {
super(view, shadowViewDelegate);
-
- mInterpolator = view.isInEditMode() ? null
- : AnimationUtils.loadInterpolator(mView.getContext(),
- android.R.interpolator.fast_out_slow_in);
}
@Override
@@ -85,24 +81,42 @@
}
@Override
- public void onElevationChanged(float elevation) {
- mView.setElevation(elevation);
- if (mShadowViewDelegate.isCompatPaddingEnabled()) {
- updatePadding();
- }
- }
+ void onElevationsChanged(final float elevation, final float pressedTranslationZ) {
+ final StateListAnimator stateListAnimator = new StateListAnimator();
- @Override
- void onTranslationZChanged(float translationZ) {
- StateListAnimator stateListAnimator = new StateListAnimator();
- // Animate translationZ to our value when pressed or focused
- stateListAnimator.addState(PRESSED_ENABLED_STATE_SET,
- setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", translationZ)));
- stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET,
- setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", translationZ)));
- // Animate translationZ to 0 otherwise
- stateListAnimator.addState(EMPTY_STATE_SET,
- setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", 0f)));
+ // Animate elevation and translationZ to our values when pressed
+ AnimatorSet set = new AnimatorSet();
+ set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation));
+ set.play(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));
+ set.play(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.play(ObjectAnimator.ofFloat(mView, "elevation", elevation));
+ Animator anim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f);
+ anim.setDuration(PRESSED_ANIM_DURATION);
+ anim.setStartDelay(PRESSED_ANIM_DELAY);
+ set.play(anim);
+ 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));
+ set.play(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f));
+ set.setInterpolator(ANIM_INTERPOLATOR);
+ stateListAnimator.addState(EMPTY_STATE_SET, set);
+
mView.setStateListAnimator(stateListAnimator);
if (mShadowViewDelegate.isCompatPaddingEnabled()) {
@@ -146,11 +160,6 @@
return false;
}
- private Animator setupAnimator(Animator animator) {
- animator.setInterpolator(mInterpolator);
- return animator;
- }
-
@Override
CircularBorderDrawable newCircularDrawable() {
return new CircularBorderDrawableLollipop();