diff --git a/lib/src/android/support/design/stateful/ExtendableSavedState.java b/lib/src/android/support/design/stateful/ExtendableSavedState.java
index cb735c069..9ef4f01b8 100644
--- a/lib/src/android/support/design/stateful/ExtendableSavedState.java
+++ b/lib/src/android/support/design/stateful/ExtendableSavedState.java
@@ -16,23 +16,21 @@
package android.support.design.stateful;
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.RestrictTo;
import android.support.v4.util.SimpleArrayMap;
import android.support.v4.view.AbsSavedState;
/**
- * Class for widgets that want to save and restore their own state in {@link
+ * SavedState for widgets that want to save and restore their own state in {@link
* android.view.View#onSaveInstanceState()}. Supports widgets whose state is composed or delegated
* out to multiple components.
*
- * @hide
+ *
Widgets with only composed or delegated state can directly instantiate this class and write to
+ * {@link #extendableStates}. Widgets with additional state should subclass ExtendableSavedState
+ * rather than trying to force the additional state into {@link #extendableStates}.
*/
-@RestrictTo(LIBRARY_GROUP)
public class ExtendableSavedState extends AbsSavedState {
public final SimpleArrayMap extendableStates;
diff --git a/lib/src/android/support/design/widget/FloatingActionButton.java b/lib/src/android/support/design/widget/FloatingActionButton.java
index 63e606ec2..98c9d69f5 100644
--- a/lib/src/android/support/design/widget/FloatingActionButton.java
+++ b/lib/src/android/support/design/widget/FloatingActionButton.java
@@ -38,7 +38,7 @@ import android.support.annotation.VisibleForTesting;
import android.support.design.R;
import android.support.design.stateful.ExtendableSavedState;
import android.support.design.widget.FloatingActionButtonImpl.InternalVisibilityChangedListener;
-import android.support.design.widget.expandable.ExpandableWidget;
+import android.support.design.widget.expandable.ExpandableTransformationWidget;
import android.support.design.widget.expandable.ExpandableWidgetHelper;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.AppCompatImageHelper;
@@ -69,9 +69,11 @@ import java.util.List;
* #setBackgroundTintList(ColorStateList)}.
*/
@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)
-public class FloatingActionButton extends VisibilityAwareImageButton implements ExpandableWidget {
+public class FloatingActionButton extends VisibilityAwareImageButton
+ implements ExpandableTransformationWidget {
private static final String LOG_TAG = "FloatingActionButton";
+ private static final String EXPANDABLE_WIDGET_HELPER_KEY = "expandableWidgetHelper";
/** Callback to be invoked when the visibility of a FloatingActionButton changes. */
public abstract static class OnVisibilityChangedListener {
@@ -359,8 +361,8 @@ public class FloatingActionButton extends VisibilityAwareImageButton implements
}
@Override
- public void setExpanded(boolean expanded) {
- expandableWidgetHelper.setExpanded(expanded);
+ public boolean setExpanded(boolean expanded) {
+ return expandableWidgetHelper.setExpanded(expanded);
}
@Override
@@ -506,7 +508,7 @@ public class FloatingActionButton extends VisibilityAwareImageButton implements
ExtendableSavedState state = new ExtendableSavedState(superState);
state.extendableStates.put(
- "expandableWidgetHelper", expandableWidgetHelper.onSaveInstanceState());
+ EXPANDABLE_WIDGET_HELPER_KEY, expandableWidgetHelper.onSaveInstanceState());
return state;
}
@@ -522,7 +524,7 @@ public class FloatingActionButton extends VisibilityAwareImageButton implements
super.onRestoreInstanceState(ess.getSuperState());
expandableWidgetHelper.onRestoreInstanceState(
- ess.extendableStates.get("expandableWidgetHelper"));
+ ess.extendableStates.get(EXPANDABLE_WIDGET_HELPER_KEY));
}
/**
diff --git a/lib/src/android/support/design/widget/expandable/ExpandableTransformationWidget.java b/lib/src/android/support/design/widget/expandable/ExpandableTransformationWidget.java
new file mode 100644
index 000000000..24731bc14
--- /dev/null
+++ b/lib/src/android/support/design/widget/expandable/ExpandableTransformationWidget.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.design.widget.expandable;
+
+import android.support.annotation.IdRes;
+
+/**
+ * An ExpandableWidget that visually transforms into another component when expanded.
+ */
+public interface ExpandableTransformationWidget extends ExpandableWidget {
+
+ /** Returns the expanded component id hint. */
+ @IdRes
+ int getExpandedComponentIdHint();
+
+ /**
+ * Sets the expanded component id hint, which may be used by a Behavior to determine whether it
+ * should handle this widget's state change.
+ */
+ void setExpandedComponentIdHint(@IdRes int expandedComponentIdHint);
+}
diff --git a/lib/src/android/support/design/widget/expandable/ExpandableWidget.java b/lib/src/android/support/design/widget/expandable/ExpandableWidget.java
index 34e3045d2..3bafd26c8 100644
--- a/lib/src/android/support/design/widget/expandable/ExpandableWidget.java
+++ b/lib/src/android/support/design/widget/expandable/ExpandableWidget.java
@@ -16,29 +16,60 @@
package android.support.design.widget.expandable;
-import android.support.annotation.IdRes;
-
/**
- * A widget that has expanded/collapsed state.
+ * A widget that has expanded/collapsed state. When the expanded state changes, {@link
+ * android.support.design.widget.CoordinatorLayout#dispatchDependentViewsChanged an event is
+ * dispatched} so that other widgets may react via a {@link
+ * android.support.design.widget.CoordinatorLayout.Behavior}.
*
- * When the expanded state changes, an event is dispatched so that other widgets may react via a
- * {@link android.support.design.widget.CoordinatorLayout.Behavior}.
+ *
Implementations of this interface should create an instance of {@link ExpandableWidgetHelper}
+ * and forward all calls to it.
+ *
+ *
The expanded state can saved across configuration changes by implementing {@link
+ * #onSaveInstanceState} and {@link #onRestoreInstanceState}:
+ *
+ *
+ * {@literal @}Override
+ * protected Parcelable onSaveInstanceState() {
+ * Parcelable superState = super.onSaveInstanceState();
+ * ExtendableSavedState state = new ExtendableSavedState(superState);
+ *
+ * state.extendableStates.put(
+ * "expandableWidgetHelper", expandableWidgetHelper.onSaveInstanceState());
+ *
+ * return state;
+ * }
+ *
+ * {@literal @}Override
+ * protected void onRestoreInstanceState(Parcelable state) {
+ * if (!(state instanceof ExtendableSavedState)) {
+ * super.onRestoreInstanceState(state);
+ * return;
+ * }
+ *
+ * ExtendableSavedState ess = (ExtendableSavedState) state;
+ * super.onRestoreInstanceState(ess.getSuperState());
+ *
+ * expandableWidgetHelper.onRestoreInstanceState(
+ * ess.extendableStates.get("expandableWidgetHelper"));
+ * }
+ *
*/
public interface ExpandableWidget {
- /** Returns whether this widget is expanded. */
+ /**
+ * Returns whether this widget is expanded.
+ *
+ * Implementations should call {@link ExpandableWidgetHelper#isExpanded()}.
+ */
boolean isExpanded();
- /** Sets the expanded state on this widget. */
- void setExpanded(boolean expanded);
-
- /** Returns the expanded component id hint. */
- @IdRes
- int getExpandedComponentIdHint();
-
/**
- * Sets the expanded component id hint, which may be used by a Behavior to determine whether it
- * should handle this widget's state change.
+ * Sets the expanded state on this widget.
+ *
+ *
Implementations should call {@link ExpandableWidgetHelper#setExpanded(boolean)}.
+ *
+ * @return true if the expanded state changed as a result of this call.
*/
- void setExpandedComponentIdHint(@IdRes int expandedComponentIdHint);
+ boolean setExpanded(boolean expanded);
}
diff --git a/lib/src/android/support/design/widget/expandable/ExpandableWidgetHelper.java b/lib/src/android/support/design/widget/expandable/ExpandableWidgetHelper.java
index ebb2c1745..0be36cba9 100644
--- a/lib/src/android/support/design/widget/expandable/ExpandableWidgetHelper.java
+++ b/lib/src/android/support/design/widget/expandable/ExpandableWidgetHelper.java
@@ -24,27 +24,30 @@ import android.view.View;
import android.view.ViewParent;
/**
- * ExpandableWidgetHelper is a helper class for writing custom {@link ExpandableWidget
- * ExpandableWidgets}. Please see each method's documentation when implementing your custom class.
+ * ExpandableWidgetHelper is a helper class for writing custom {@link ExpandableWidget}s and {@link
+ * ExpandableTransformationWidget}. Please see the interface documentation when implementing your
+ * custom class.
*/
public final class ExpandableWidgetHelper {
private final View widget;
- private boolean expanded;
- @IdRes private int expandedComponentIdHint;
+ private boolean expanded = false;
+ @IdRes private int expandedComponentIdHint = 0;
/** Call this from the constructor. */
- public ExpandableWidgetHelper(T widget) {
- this.widget = widget;
+ public ExpandableWidgetHelper(ExpandableWidget widget) {
+ this.widget = (View) widget;
}
/** Call this from {@link ExpandableWidget#setExpanded(boolean)}. */
- public void setExpanded(boolean expanded) {
+ public boolean setExpanded(boolean expanded) {
if (this.expanded != expanded) {
this.expanded = expanded;
dispatchExpandedStateChanged();
+ return true;
}
+ return false;
}
/** Call this from {@link ExpandableWidget#isExpanded()}. */
@@ -52,20 +55,7 @@ public final class ExpandableWidgetHelper {
return expanded;
}
- /** Call this from {@link ExpandableWidget#setExpandedComponentIdHint(int)}. */
- public void setExpandedComponentIdHint(@IdRes int expandedComponentIdHint) {
- this.expandedComponentIdHint = expandedComponentIdHint;
- }
-
- /** Call this from {@link ExpandableWidget#getExpandedComponentIdHint()}. */
- @IdRes
- public int getExpandedComponentIdHint() {
- return expandedComponentIdHint;
- }
-
- /**
- * Call this from {@link View#onSaveInstanceState()} after your widget's custom state is saved.
- */
+ /** Call this from {@link View#onSaveInstanceState()}. */
public Bundle onSaveInstanceState() {
Bundle state = new Bundle();
state.putBoolean("expanded", expanded);
@@ -74,10 +64,7 @@ public final class ExpandableWidgetHelper {
return state;
}
- /**
- * Call this from {@link View#onRestoreInstanceState(Parcelable)} after your widget's custom state
- * is restored.
- */
+ /** Call this from {@link View#onRestoreInstanceState(Parcelable)}. */
public void onRestoreInstanceState(Bundle state) {
expanded = state.getBoolean("expanded", false);
expandedComponentIdHint = state.getInt("expandedComponentIdHint", 0);
@@ -87,6 +74,17 @@ public final class ExpandableWidgetHelper {
}
}
+ /** Call this from {@link ExpandableTransformationWidget#setExpandedComponentIdHint(int)}. */
+ public void setExpandedComponentIdHint(@IdRes int expandedComponentIdHint) {
+ this.expandedComponentIdHint = expandedComponentIdHint;
+ }
+
+ /** Call this from {@link ExpandableTransformationWidget#getExpandedComponentIdHint()}. */
+ @IdRes
+ public int getExpandedComponentIdHint() {
+ return expandedComponentIdHint;
+ }
+
private void dispatchExpandedStateChanged() {
ViewParent parent = widget.getParent();
if (parent instanceof CoordinatorLayout) {
diff --git a/lib/src/android/support/design/widget/transformation/ExpandableBehavior.java b/lib/src/android/support/design/widget/transformation/ExpandableBehavior.java
new file mode 100644
index 000000000..2827e16b0
--- /dev/null
+++ b/lib/src/android/support/design/widget/transformation/ExpandableBehavior.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.design.widget.transformation;
+
+import android.content.Context;
+import android.support.annotation.CallSuper;
+import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
+import android.support.design.widget.CoordinatorLayout;
+import android.support.design.widget.CoordinatorLayout.Behavior;
+import android.support.design.widget.expandable.ExpandableWidget;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Base Behavior for views that can react to an {@link ExpandableWidget}'s {@link
+ * ExpandableWidget#setExpanded(boolean)} state changes.
+ */
+public abstract class ExpandableBehavior extends Behavior {
+
+ /** Unknown expanded state. */
+ private static final int STATE_UNKNOWN = 0;
+ /** Expanded state. */
+ private static final int STATE_EXPANDED = 1;
+ /** Collapsed state. */
+ private static final int STATE_COLLAPSED = 2;
+
+ @IntDef({STATE_UNKNOWN, STATE_EXPANDED, STATE_COLLAPSED})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface State {}
+
+ /**
+ * The current expanded state of this behavior. This state follows the expanded state of the
+ * {@link ExpandableWidget} dependency, and is updated in {@link #onLayoutChild(CoordinatorLayout,
+ * View, int)} and {@link #onDependentViewChanged(CoordinatorLayout, View, View)}.
+ *
+ * This state may be {@link #STATE_UNKNOWN} before either of those callbacks have been invoked.
+ */
+ @State private int currentState = STATE_UNKNOWN;
+
+ public ExpandableBehavior() {}
+
+ public ExpandableBehavior(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public abstract boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency);
+
+ /**
+ * Reacts to a change in expanded state. This callback is guaranteed to be called only once even
+ * if {@link ExpandableWidget#setExpanded(boolean)} is called multiple times with the same value.
+ * Upon configuration change, this callback is called with {@code animated} set to false.
+ *
+ * @param dependency the {@link ExpandableWidget} dependency containing the new expanded state.
+ * @param child the view that should react to the change in expanded state.
+ * @param expanded the new expanded state.
+ * @param animated true if {@link ExpandableWidget#setExpanded(boolean)} was called, false if
+ * restoring from a configuration change.
+ * @return true if the Behavior changed the child view's size or position, false otherwise.
+ */
+ protected abstract boolean onExpandedStateChange(
+ ExpandableWidget dependency, View child, boolean expanded, boolean animated);
+
+ @CallSuper
+ @Override
+ public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
+ if (!ViewCompat.isLaidOut(child)) {
+ ExpandableWidget dep = findExpandableWidget(parent, child);
+ if (dep != null) {
+ currentState = dep.isExpanded() ? STATE_EXPANDED : STATE_COLLAPSED;
+ onExpandedStateChange(dep, child, dep.isExpanded(), false);
+ }
+ }
+
+ return false;
+ }
+
+ @CallSuper
+ @Override
+ public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
+ ExpandableWidget dep = (ExpandableWidget) dependency;
+ boolean expanded = dep.isExpanded();
+ if (didStateChange(expanded)) {
+ currentState = dep.isExpanded() ? STATE_EXPANDED : STATE_COLLAPSED;
+ return onExpandedStateChange(dep, child, dep.isExpanded(), true);
+ }
+
+ return false;
+ }
+
+ @Nullable
+ protected ExpandableWidget findExpandableWidget(CoordinatorLayout parent, View child) {
+ List dependencies = parent.getDependencies(child);
+ for (int i = 0, size = dependencies.size(); i < size; i++) {
+ View dependency = dependencies.get(i);
+ if (layoutDependsOn(parent, child, dependency)) {
+ return (ExpandableWidget) dependency;
+ }
+ }
+ return null;
+ }
+
+ private boolean didStateChange(boolean expanded) {
+ return (expanded && ((currentState == STATE_UNKNOWN) || (currentState == STATE_COLLAPSED)))
+ || (!expanded && ((currentState == STATE_UNKNOWN) || (currentState == STATE_EXPANDED)));
+ }
+
+ /**
+ * A utility function to get the {@link ExpandableBehavior} attached to the {@code view}.
+ *
+ * @param view The {@link View} that the {@link ExpandableBehavior} is attached to.
+ * @param klass The expected {@link Class} of the attached {@link ExpandableBehavior}.
+ * @return The {@link ExpandableBehavior} attached to the {@code view}.
+ */
+ public static T from(View view, Class klass) {
+ ViewGroup.LayoutParams params = view.getLayoutParams();
+ if (!(params instanceof CoordinatorLayout.LayoutParams)) {
+ throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
+ }
+ CoordinatorLayout.Behavior> behavior =
+ ((CoordinatorLayout.LayoutParams) params).getBehavior();
+ if (!(behavior instanceof ExpandableBehavior)) {
+ throw new IllegalArgumentException("The view is not associated with ExpandableBehavior");
+ }
+ return klass.cast(behavior);
+ }
+}
diff --git a/lib/src/android/support/design/widget/transformation/ExpandableTransformationBehavior.java b/lib/src/android/support/design/widget/transformation/ExpandableTransformationBehavior.java
index 7ee6357a3..e031fa228 100644
--- a/lib/src/android/support/design/widget/transformation/ExpandableTransformationBehavior.java
+++ b/lib/src/android/support/design/widget/transformation/ExpandableTransformationBehavior.java
@@ -19,44 +19,22 @@ package android.support.design.widget.transformation;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
-import android.support.annotation.IntDef;
+import android.support.annotation.CallSuper;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.design.widget.CoordinatorLayout;
-import android.support.design.widget.CoordinatorLayout.Behavior;
import android.support.design.widget.expandable.ExpandableWidget;
-import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewGroup;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
/**
- * Base Behavior for views that a {@link ExpandableWidget} can transform into. Reacts to {@link
- * ExpandableWidget#setExpanded(boolean)} state changes with an animation.
+ * Base Behavior for views that can react to an {@link ExpandableWidget}'s {@link
+ * ExpandableWidget#setExpanded(boolean)} state changes by transforming the ExpandableWidget into
+ * itself.
+ *
+ * Behaviors should override {@link #onCreateExpandedStateChangeAnimation(ExpandableWidget, View,
+ * boolean)} to return an animation
*/
-public abstract class ExpandableTransformationBehavior extends Behavior {
-
- /** Unknown expanded state. */
- private static final int STATE_UNKNOWN = 0;
- /** Expanded state. */
- private static final int STATE_EXPANDED = 1;
- /** Collapsed state. */
- private static final int STATE_COLLAPSED = 2;
-
- @IntDef({STATE_UNKNOWN, STATE_EXPANDED, STATE_COLLAPSED})
- @Retention(RetentionPolicy.SOURCE)
- private @interface State {}
-
- /**
- * The current expanded state of this behavior. This state follows the expanded state of the
- * {@link ExpandableWidget} dependency, and is updated in {@link #onLayoutChild(CoordinatorLayout,
- * View, int)} and {@link #onDependentViewChanged(CoordinatorLayout, View, View)}.
- *
- * This state may be {@link #STATE_UNKNOWN} before either of those callbacks have been invoked.
- */
- @State private int currentState = STATE_UNKNOWN;
+public abstract class ExpandableTransformationBehavior extends ExpandableBehavior {
@Nullable private Animator currentAnimation;
@@ -66,109 +44,46 @@ public abstract class ExpandableTransformationBehavior extends Behavior {
super(context, attrs);
}
+ /**
+ * Creates an Animator to be played for this expanded state change.
+ *
+ * If the new {@code expanded} state is true, the {@code dependency} should be hidden and the
+ * {@code child} should be shown.
+ *
+ *
If the new {@code expanded} state is false, the {@code dependency} should be shown and the
+ * {@code child} should be hidden.
+ *
+ * @param dependency the {@link ExpandableWidget} dependency containing the new expanded state.
+ * @param child the view that should react to the change in expanded state.
+ * @param expanded the new expanded state.
+ */
+ @NonNull
+ protected abstract Animator onCreateExpandedStateChangeAnimation(
+ ExpandableWidget dependency, View child, boolean expanded);
+
+ @CallSuper
@Override
- public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
- return dependency instanceof ExpandableWidget;
- }
-
- @Override
- public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
- if (!ViewCompat.isLaidOut(child)) {
- List dependencies = parent.getDependencies(child);
- ExpandableWidget dependency = findExpandableWidget(dependencies);
- jumpToState(dependency, child);
- }
-
- return false;
- }
-
- @Override
- public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
- ExpandableWidget dep = (ExpandableWidget) dependency;
- boolean expanded = dep.isExpanded();
- if (!didStateChange(expanded)) {
- return false;
- }
-
+ protected boolean onExpandedStateChange(
+ ExpandableWidget dependency, View child, boolean expanded, boolean animated) {
if (currentAnimation != null) {
currentAnimation.cancel();
}
- currentState = expanded ? STATE_EXPANDED : STATE_COLLAPSED;
- currentAnimation = createAnimation(dep, child);
+ currentAnimation = onCreateExpandedStateChangeAnimation(dependency, child, expanded);
currentAnimation.addListener(
new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- if (expanded) {
- child.setVisibility(View.VISIBLE);
- }
- }
-
@Override
public void onAnimationEnd(Animator animation) {
- if (!expanded) {
- child.setVisibility(View.INVISIBLE);
- }
currentAnimation = null;
}
});
+
currentAnimation.start();
+ if (!animated) {
+ // Synchronously end the animation, jumping to the end state.
+ currentAnimation.end();
+ }
+
return true;
}
-
- protected void jumpToState(ExpandableWidget dep, View child) {
- boolean expanded = dep.isExpanded();
- if (!didStateChange(expanded)) {
- return;
- }
-
- currentState = expanded ? STATE_EXPANDED : STATE_COLLAPSED;
-
- if (expanded) {
- child.setVisibility(View.VISIBLE);
- } else {
- child.setVisibility(View.INVISIBLE);
- }
- }
-
- protected abstract Animator createAnimation(ExpandableWidget dep, View child);
-
- private ExpandableWidget findExpandableWidget(List dependencies) {
- for (int i = 0, size = dependencies.size(); i < size; i++) {
- View dependency = dependencies.get(i);
- if (dependency instanceof ExpandableWidget) {
- return (ExpandableWidget) dependency;
- }
- }
- return null;
- }
-
- private boolean didStateChange(boolean expanded) {
- return (expanded && ((currentState == STATE_UNKNOWN) || (currentState == STATE_COLLAPSED)))
- || (!expanded && ((currentState == STATE_UNKNOWN) || (currentState == STATE_EXPANDED)));
- }
-
- /**
- * A utility function to get the {@link ExpandableTransformationBehavior} attached to the {@code
- * view}.
- *
- * @param view The {@link View} that the {@link ExpandableTransformationBehavior} is attached to.
- * @param klass The expected {@link Class} of the attached {@link
- * ExpandableTransformationBehavior}.
- * @return The {@link ExpandableTransformationBehavior} attached to the {@code view}.
- */
- public static T from(View view, Class klass) {
- ViewGroup.LayoutParams params = view.getLayoutParams();
- if (!(params instanceof CoordinatorLayout.LayoutParams)) {
- throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
- }
- CoordinatorLayout.Behavior> behavior =
- ((CoordinatorLayout.LayoutParams) params).getBehavior();
- if (!(behavior instanceof ExpandableTransformationBehavior)) {
- throw new IllegalArgumentException(
- "The view is not associated with ExpandableTransformationBehavior");
- }
- return klass.cast(view);
- }
}
diff --git a/lib/src/android/support/design/widget/transformation/FabTransformationScrimBehavior.java b/lib/src/android/support/design/widget/transformation/FabTransformationScrimBehavior.java
index 044e51099..12641f8c0 100644
--- a/lib/src/android/support/design/widget/transformation/FabTransformationScrimBehavior.java
+++ b/lib/src/android/support/design/widget/transformation/FabTransformationScrimBehavior.java
@@ -17,9 +17,11 @@
package android.support.design.widget.transformation;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.expandable.ExpandableWidget;
@@ -30,8 +32,8 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Behavior that should be attached to a scrim that should appear when a {@link ExpandableWidget} is
- * {@link ExpandableWidget#setExpanded(boolean)} expanded}.
+ * Behavior that should be attached to a scrim that should appear when a {@link
+ * FloatingActionButton} is {@link FloatingActionButton#setExpanded(boolean)} expanded}.
*/
public class FabTransformationScrimBehavior extends ExpandableTransformationBehavior {
@@ -44,8 +46,7 @@ public class FabTransformationScrimBehavior extends ExpandableTransformationBeha
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
- return super.layoutDependsOn(parent, child, dependency)
- && dependency instanceof FloatingActionButton;
+ return dependency instanceof FloatingActionButton;
}
@Override
@@ -54,17 +55,35 @@ public class FabTransformationScrimBehavior extends ExpandableTransformationBeha
return super.onTouchEvent(parent, child, ev);
}
+ @NonNull
@Override
- protected Animator createAnimation(ExpandableWidget dep, View child) {
+ protected Animator onCreateExpandedStateChangeAnimation(
+ ExpandableWidget dep, View child, boolean expanded) {
List animations = new ArrayList<>();
- if (dep.isExpanded()) {
+ if (expanded) {
animations.add(ObjectAnimator.ofFloat(child, View.ALPHA, 0f, 1f));
} else {
animations.add(ObjectAnimator.ofFloat(child, View.ALPHA, 1f, 0f));
}
AnimatorSet set = new AnimatorSet();
+ set.addListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (expanded) {
+ child.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!expanded) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ }
+ });
set.playTogether(animations);
return set;
}
diff --git a/lib/src/android/support/design/widget/transformation/FabTransformationSheetBehavior.java b/lib/src/android/support/design/widget/transformation/FabTransformationSheetBehavior.java
index e5f826fca..55dcca20b 100644
--- a/lib/src/android/support/design/widget/transformation/FabTransformationSheetBehavior.java
+++ b/lib/src/android/support/design/widget/transformation/FabTransformationSheetBehavior.java
@@ -32,8 +32,8 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Behavior that should be attached to any sheet that should appear when a {@link ExpandableWidget}
- * is {@link ExpandableWidget#setExpanded(boolean)} expanded}.
+ * Behavior that should be attached to any sheet that should appear when a {@link
+ * FloatingActionButton} is {@link FloatingActionButton#setExpanded(boolean)} expanded}.
*
* A sheet usually has some width and height that's smaller than the screen, has an elevation,
* and may have a scrim underneath.
@@ -49,8 +49,7 @@ public class FabTransformationSheetBehavior extends ExpandableTransformationBeha
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
- return super.layoutDependsOn(parent, child, dependency)
- && dependency instanceof FloatingActionButton;
+ return dependency instanceof FloatingActionButton;
}
@Override
@@ -62,32 +61,18 @@ public class FabTransformationSheetBehavior extends ExpandableTransformationBeha
}
}
+ @NonNull
@Override
- protected void jumpToState(ExpandableWidget dep, View child) {
- super.jumpToState(dep, child);
-
- View dependency = (View) dep;
- if (dep.isExpanded()) {
- // A bug exists in 4.4.4 where setVisibility() did not invalidate the view.
- dependency.setAlpha(0f);
- dependency.setVisibility(View.INVISIBLE);
- } else {
- // A bug exists in 4.4.4 where setVisibility() did not invalidate the view.
- dependency.setAlpha(1f);
- dependency.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- protected Animator createAnimation(ExpandableWidget dep, View child) {
+ protected Animator onCreateExpandedStateChangeAnimation(
+ ExpandableWidget dependency, View child, boolean expanded) {
List animations = new ArrayList<>();
- View dependency = (View) dep;
- if (dep.isExpanded()) {
- animations.add(ObjectAnimator.ofFloat(dependency, View.ALPHA, 1f, 0f));
+ View dep = (View) dependency;
+ if (expanded) {
+ animations.add(ObjectAnimator.ofFloat(dep, View.ALPHA, 1f, 0f));
animations.add(ObjectAnimator.ofFloat(child, View.ALPHA, 0f, 1f));
} else {
- animations.add(ObjectAnimator.ofFloat(dependency, View.ALPHA, 0f, 1f));
+ animations.add(ObjectAnimator.ofFloat(dep, View.ALPHA, 0f, 1f));
animations.add(ObjectAnimator.ofFloat(child, View.ALPHA, 1f, 0f));
}
@@ -97,19 +82,23 @@ public class FabTransformationSheetBehavior extends ExpandableTransformationBeha
new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- if (!dep.isExpanded()) {
+ if (expanded) {
+ child.setVisibility(View.VISIBLE);
+ } else {
// A bug exists in 4.4.4 where setVisibility() did not invalidate the view.
- dependency.setAlpha(1f);
- dependency.setVisibility(View.VISIBLE);
+ dep.setAlpha(1f);
+ dep.setVisibility(View.VISIBLE);
}
}
@Override
public void onAnimationEnd(Animator animation) {
- if (dep.isExpanded()) {
+ if (expanded) {
// A bug exists in 4.4.4 where setVisibility() did not invalidate the view.
- dependency.setAlpha(0f);
- dependency.setVisibility(View.INVISIBLE);
+ dep.setAlpha(0f);
+ dep.setVisibility(View.INVISIBLE);
+ } else {
+ child.setVisibility(View.INVISIBLE);
}
}
});