mirror of
https://github.com/material-components/material-components-android.git
synced 2026-02-20 08:39:55 +08:00
Merge \"Fix FloatingActionButton hide() and show()\" into nyc-support-24.1-dev
am: dfc69f69f1 Change-Id: I1d26458467f4fcd154c179c3ce5e2810d0ae69e5 GitOrigin-RevId=49886f03824b46ae35cd649fddc85d26d1da7372 PiperOrigin-RevId: 140564038
This commit is contained in:
parent
554c03b354
commit
2ca8076b0a
@ -25,7 +25,11 @@ import android.view.View;
|
||||
|
||||
class FloatingActionButtonIcs extends FloatingActionButtonGingerbread {
|
||||
|
||||
private boolean mIsHiding;
|
||||
private static final int ANIM_STATE_NONE = 0;
|
||||
private static final int ANIM_STATE_HIDING = 1;
|
||||
private static final int ANIM_STATE_SHOWING = 2;
|
||||
|
||||
private int mAnimState = ANIM_STATE_NONE;
|
||||
private float mRotation;
|
||||
|
||||
FloatingActionButtonIcs(VisibilityAwareImageButton view,
|
||||
@ -50,22 +54,16 @@ class FloatingActionButtonIcs extends FloatingActionButtonGingerbread {
|
||||
|
||||
@Override
|
||||
void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
|
||||
if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
|
||||
// A hide animation is in progress, or we're already hidden. Skip the call
|
||||
if (listener != null) {
|
||||
listener.onHidden();
|
||||
}
|
||||
if (isOrWillBeHidden()) {
|
||||
// We either are or will soon be hidden, skip the call
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ViewCompat.isLaidOut(mView) || mView.isInEditMode()) {
|
||||
// If the view isn't laid out, or we're in the editor, don't run the animation
|
||||
mView.internalSetVisibility(View.GONE, fromUser);
|
||||
if (listener != null) {
|
||||
listener.onHidden();
|
||||
}
|
||||
} else {
|
||||
mView.animate().cancel();
|
||||
mView.animate().cancel();
|
||||
|
||||
if (shouldAnimateVisibilityChange()) {
|
||||
mAnimState = ANIM_STATE_HIDING;
|
||||
|
||||
mView.animate()
|
||||
.scaleX(0f)
|
||||
.scaleY(0f)
|
||||
@ -77,20 +75,19 @@ class FloatingActionButtonIcs extends FloatingActionButtonGingerbread {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mIsHiding = true;
|
||||
mCancelled = false;
|
||||
mView.internalSetVisibility(View.VISIBLE, fromUser);
|
||||
mCancelled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mIsHiding = false;
|
||||
mCancelled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mIsHiding = false;
|
||||
mAnimState = ANIM_STATE_NONE;
|
||||
|
||||
if (!mCancelled) {
|
||||
mView.internalSetVisibility(View.GONE, fromUser);
|
||||
if (listener != null) {
|
||||
@ -99,51 +96,89 @@ class FloatingActionButtonIcs extends FloatingActionButtonGingerbread {
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// If the view isn't laid out, or we're in the editor, don't run the animation
|
||||
mView.internalSetVisibility(View.GONE, fromUser);
|
||||
if (listener != null) {
|
||||
listener.onHidden();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
|
||||
if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
|
||||
if (ViewCompat.isLaidOut(mView) && !mView.isInEditMode()) {
|
||||
mView.animate().cancel();
|
||||
if (mView.getVisibility() != View.VISIBLE) {
|
||||
// If the view isn't visible currently, we'll animate it from a single pixel
|
||||
mView.setAlpha(0f);
|
||||
mView.setScaleY(0f);
|
||||
mView.setScaleX(0f);
|
||||
}
|
||||
mView.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.alpha(1f)
|
||||
.setDuration(SHOW_HIDE_ANIM_DURATION)
|
||||
.setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mView.internalSetVisibility(View.VISIBLE, fromUser);
|
||||
}
|
||||
if (isOrWillBeShown()) {
|
||||
// We either are or will soon be visible, skip the call
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (listener != null) {
|
||||
listener.onShown();
|
||||
}
|
||||
mView.animate().cancel();
|
||||
|
||||
if (shouldAnimateVisibilityChange()) {
|
||||
mAnimState = ANIM_STATE_SHOWING;
|
||||
|
||||
if (mView.getVisibility() != View.VISIBLE) {
|
||||
// If the view isn't visible currently, we'll animate it from a single pixel
|
||||
mView.setAlpha(0f);
|
||||
mView.setScaleY(0f);
|
||||
mView.setScaleX(0f);
|
||||
}
|
||||
|
||||
mView.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.alpha(1f)
|
||||
.setDuration(SHOW_HIDE_ANIM_DURATION)
|
||||
.setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mView.internalSetVisibility(View.VISIBLE, fromUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mAnimState = ANIM_STATE_NONE;
|
||||
if (listener != null) {
|
||||
listener.onShown();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mView.internalSetVisibility(View.VISIBLE, fromUser);
|
||||
mView.setAlpha(1f);
|
||||
mView.setScaleY(1f);
|
||||
mView.setScaleX(1f);
|
||||
if (listener != null) {
|
||||
listener.onShown();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mView.internalSetVisibility(View.VISIBLE, fromUser);
|
||||
mView.setAlpha(1f);
|
||||
mView.setScaleY(1f);
|
||||
mView.setScaleX(1f);
|
||||
if (listener != null) {
|
||||
listener.onShown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOrWillBeShown() {
|
||||
if (mView.getVisibility() != View.VISIBLE) {
|
||||
// If we not currently visible, return true if we're animating to be shown
|
||||
return mAnimState == ANIM_STATE_SHOWING;
|
||||
} else {
|
||||
// Otherwise if we're visible, return true if we're not animating to be hidden
|
||||
return mAnimState != ANIM_STATE_HIDING;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOrWillBeHidden() {
|
||||
if (mView.getVisibility() == View.VISIBLE) {
|
||||
// If we currently visible, return true if we're animating to be hidden
|
||||
return mAnimState == ANIM_STATE_HIDING;
|
||||
} else {
|
||||
// Otherwise if we're not visible, return true if we're not animating to be shown
|
||||
return mAnimState != ANIM_STATE_SHOWING;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldAnimateVisibilityChange() {
|
||||
return ViewCompat.isLaidOut(mView) && !mView.isInEditMode();
|
||||
}
|
||||
|
||||
private void updateFromViewRotation() {
|
||||
if (Build.VERSION.SDK_INT == 19) {
|
||||
// KitKat seems to have an issue with views which are rotated with angles which are
|
||||
|
||||
@ -129,4 +129,54 @@ public class FloatingActionButtonActions {
|
||||
};
|
||||
}
|
||||
|
||||
public static ViewAction hideThenShow(final int animDuration) {
|
||||
return new ViewAction() {
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isAssignableFrom(FloatingActionButton.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Calls hide() then show()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
uiController.loopMainThreadUntilIdle();
|
||||
|
||||
FloatingActionButton fab = (FloatingActionButton) view;
|
||||
fab.hide();
|
||||
fab.show();
|
||||
|
||||
uiController.loopMainThreadForAtLeast(animDuration + 100);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static ViewAction showThenHide(final int animDuration) {
|
||||
return new ViewAction() {
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isAssignableFrom(FloatingActionButton.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Calls show() then hide()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
uiController.loopMainThreadUntilIdle();
|
||||
|
||||
FloatingActionButton fab = (FloatingActionButton) view;
|
||||
fab.show();
|
||||
fab.hide();
|
||||
|
||||
uiController.loopMainThreadForAtLeast(animDuration + 50);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -16,15 +16,19 @@
|
||||
|
||||
package android.support.design.widget;
|
||||
|
||||
import static android.support.design.testutils.FloatingActionButtonActions.hideThenShow;
|
||||
import static android.support.design.testutils.FloatingActionButtonActions.setBackgroundTintColor;
|
||||
import static android.support.design.testutils.FloatingActionButtonActions.setImageResource;
|
||||
import static android.support.design.testutils.FloatingActionButtonActions.setLayoutGravity;
|
||||
import static android.support.design.testutils.FloatingActionButtonActions.setSize;
|
||||
import static android.support.design.testutils.FloatingActionButtonActions.showThenHide;
|
||||
import static android.support.design.testutils.TestUtilsMatchers.withFabBackgroundFill;
|
||||
import static android.support.design.testutils.TestUtilsMatchers.withFabContentAreaOnMargins;
|
||||
import static android.support.design.testutils.TestUtilsMatchers.withFabContentHeight;
|
||||
import static android.support.design.widget.DesignViewActions.setVisibility;
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
|
||||
import android.graphics.Color;
|
||||
@ -32,6 +36,7 @@ import android.support.design.test.R;
|
||||
import android.support.design.testutils.TestUtils;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@ -114,4 +119,20 @@ public class FloatingActionButtonTest
|
||||
.check(matches(withFabContentAreaOnMargins(Gravity.RIGHT | Gravity.BOTTOM)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHideShow() {
|
||||
onView(withId(R.id.fab_standard))
|
||||
.perform(setVisibility(View.VISIBLE))
|
||||
.perform(hideThenShow(FloatingActionButtonImpl.SHOW_HIDE_ANIM_DURATION))
|
||||
.check(matches(isDisplayed()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowHide() {
|
||||
onView(withId(R.id.fab_standard))
|
||||
.perform(setVisibility(View.GONE))
|
||||
.perform(showThenHide(FloatingActionButtonImpl.SHOW_HIDE_ANIM_DURATION))
|
||||
.check(matches(not(isDisplayed())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user