Instantly share code, notes, and snippets.
Forked from NikolaDespotoski/FloatingActionMenuBehavior.java
Created
September 21, 2015 01:50
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save goodev/ff3b5f59eef251c6474b to your computer and use it in GitHub Desktop.
FloatingActionMenuBehavior for FloatingActionsMenu library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//https://medium.com/@nullthemall/floatingactionmenu-floatingactionbutton-behavior-dd33cc0d9ba7 | |
public class FloatingActionMenuBehavior extends android.support.design.widget.CoordinatorLayout.Behavior<FloatingActionsMenu> { | |
private static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutLinearInInterpolator(); | |
private int mTotalDy = 0; | |
private boolean isAnimating = false; | |
private FloatingActionsMenu.OnFloatingActionsMenuUpdateListener mFloatingMenuUpdateListener = new FloatingActionsMenu.OnFloatingActionsMenuUpdateListener() { | |
@Override | |
public void onMenuExpanded() { | |
isAnimating = false; | |
} | |
@Override | |
public void onMenuCollapsed() { | |
isAnimating = false; | |
} | |
}; | |
public FloatingActionMenuBehavior() { | |
} | |
public FloatingActionMenuBehavior(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
@Override | |
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionsMenu child, View dependency) { | |
if (dependency instanceof Snackbar.SnackbarLayout) { | |
updateFabTranslationForSnackbar(child, dependency); | |
} | |
return false; | |
} | |
private void updateFabTranslationForSnackbar(FloatingActionsMenu child, View dependency) { | |
float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight()); | |
ViewCompat.setTranslationX(child, translationY); | |
} | |
@Override | |
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionsMenu child, View directTargetChild, View target, int nestedScrollAxes) { | |
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL; | |
} | |
@Override | |
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionsMenu child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { | |
mTotalDy = dyConsumed < 0 && mTotalDy > 0 || dyConsumed > 0 && mTotalDy < 0 ? 0 : mTotalDy; | |
attemptCancelAnimation(child); | |
mTotalDy += dyConsumed; | |
updateFloatingActionMenu(child); | |
} | |
@Override | |
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, final FloatingActionsMenu child, View target, float velocityX, float velocityY) { | |
Log.i("onNestedPreFling", " velocityY: " + velocityY); | |
if (Math.abs(velocityY) < Math.abs(velocityX)) return false; | |
final int childCount = child.getChildCount(); | |
final View firstFab = child.getChildAt(childCount - 1); | |
if (velocityY < 0 && isScaleX(firstFab, 0f)) { | |
/* | |
Velocity is negative, we are flinging up | |
*/ | |
scaleTo(firstFab, 1f, null); | |
firstFab.setClickable(true); | |
} else if (velocityY > 0) { | |
/* | |
Velocity is positive, we are flinging down | |
*/ | |
if (child.isExpanded()) { | |
child.collapse(); | |
child.setOnFloatingActionsMenuUpdateListener(new FloatingActionsMenu.OnFloatingActionsMenuUpdateListener() { | |
@Override | |
public void onMenuExpanded() { | |
} | |
@Override | |
public void onMenuCollapsed() { | |
if (isScaleX(firstFab, 1f)) { | |
scaleTo(firstFab, 0f, null); | |
firstFab.setClickable(false); | |
} | |
} | |
}); | |
} else { | |
if (isScaleX(firstFab, 1f)) { | |
scaleTo(firstFab, 0f, null); | |
firstFab.setClickable(false); | |
} | |
} | |
} | |
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY); | |
} | |
private void attemptCancelAnimation(FloatingActionsMenu child) { | |
if (mTotalDy == 0) { | |
ViewCompat.animate(child).cancel(); | |
ViewCompat.animate(child.getChildAt(child.getChildCount() - 1)).cancel(); | |
} | |
} | |
private void updateFloatingActionMenu(final FloatingActionsMenu child) { | |
int totalHeight = child.getHeight(); | |
View firstFab = child.getChildAt(0); | |
if (child.getChildCount() > 1) { | |
/* | |
More than one fab in the menu | |
*/ | |
if (child.isExpanded()) { | |
/* | |
We have expanded menu and it needs to be collapsed, | |
when we have scrolled to the height of the menu | |
*/ | |
totalHeight -= firstFab.getHeight(); | |
if (mTotalDy > totalHeight && !isAnimating) { | |
/* | |
Scrolling down. | |
*/ | |
isAnimating = true; | |
child.collapse(); | |
child.setOnFloatingActionsMenuUpdateListener(mFloatingMenuUpdateListener); | |
} else if (mTotalDy < 0 && !child.isExpanded()) { | |
/* | |
Scrolling up | |
*/ | |
if (isScaleX(child, 0f)) { | |
scaleTo(child, 1f, null); | |
firstFab.setClickable(true); | |
} | |
} | |
} else { | |
/* | |
The menu is collapsed. We are left with only one fab. | |
*/ | |
totalHeight = firstFab.getHeight(); | |
firstFab = child.getChildAt(child.getChildCount() - 1); | |
updateFirstFloatingActionButton(firstFab, totalHeight); | |
} | |
} else { | |
// Only one fab. | |
totalHeight = child.getHeight(); | |
updateFirstFloatingActionButton(child.getChildAt(0), totalHeight); | |
} | |
} | |
private void updateFirstFloatingActionButton(View firstFab, int totalHeight) { | |
if (mTotalDy > totalHeight && isScaleX(firstFab, 1f)) { | |
firstFab.setClickable(false); | |
scaleTo(firstFab, 0f, null); | |
} else if (mTotalDy < 0 && Math.abs(mTotalDy) >= totalHeight && isScaleX(firstFab, 0f)) { | |
scaleTo(firstFab, 1f, null); | |
firstFab.setClickable(true); | |
} | |
} | |
private void scaleTo(View floatingActionButton, float value, Runnable runnable) { | |
ViewPropertyAnimatorCompat viewPropertyAnimatorCompat = ViewCompat.animate(floatingActionButton) | |
.scaleX(value).scaleY(value).setDuration(100) | |
.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR); | |
if (runnable != null) { | |
viewPropertyAnimatorCompat.withEndAction(runnable); | |
} | |
viewPropertyAnimatorCompat.start(); | |
} | |
private boolean isScaleX(View v, float value) { | |
return ViewCompat.getScaleX(v) == value; | |
} | |
@Override | |
public void onDependentViewRemoved(CoordinatorLayout parent, FloatingActionsMenu child, View dependency) { | |
if (dependency instanceof Snackbar.SnackbarLayout && ViewCompat.getTranslationY(child) != 0.0F) { | |
ViewCompat.animate(child).translationY(0.0F).scaleX(1.0F).scaleY(1.0F).alpha(1.0F).setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR).setListener((ViewPropertyAnimatorListener) null); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment