Instantly share code, notes, and snippets.
Created
March 6, 2018 12:38
-
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 Subtle-fox/b952c4c0eb8b43e063c8be329bc3dcaf to your computer and use it in GitHub Desktop.
"Floating Action Button" menu
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
/** | |
* Created by Andrey Kolpakov on 19.01.2018 | |
*/ | |
public class FabMenu { | |
private final ViewGroup parent; | |
private final Context context; | |
private final FloatingActionButton fab; | |
private boolean isFabMenuOpened; | |
private View maskedView; | |
private ArrayList<FabMenuItem> menuItems = new ArrayList<>(); | |
private ArrayList<FabMenuView> menuItemViews = new ArrayList<>(); | |
public FabMenu(ViewGroup parent, FloatingActionButton mainFab) { | |
this.parent = parent; | |
this.context = parent.getContext(); | |
this.fab = mainFab; | |
} | |
private View createMaskedView() { | |
View view = new View(context); | |
view.setBackgroundColor(ContextCompat.getColor(context, R.color.fab_menu_background)); | |
view.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
closeFabMenu(); | |
} | |
}); | |
view.setScaleX(0f); | |
view.setScaleY(0f); | |
view.setAlpha(0f); | |
return view; | |
} | |
public void addMenuItem(int imageResId, int label, View.OnClickListener action) { | |
menuItems.add(new FabMenuItem(imageResId, label, action)); | |
} | |
public void create() { | |
if (menuItems.isEmpty()) { | |
fab.setVisibility(View.GONE); | |
return; | |
} | |
maskedView = createMaskedView(); | |
if (menuItems.size() == 1) { | |
fab.setImageResource(menuItems.get(0).imageResId); | |
fab.setOnClickListener(menuItems.get(0).action); | |
} else { | |
createFabMenu(); | |
} | |
fab.show(); | |
} | |
public boolean hasItems() { | |
return menuItems.size() > 0; | |
} | |
private void createFabMenu() { | |
fab.setImageResource(R.drawable.ic_menu_hamburger); | |
fab.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
if (!isFabMenuOpened) { | |
showFabMenu(); | |
} else { | |
closeFabMenu(); | |
} | |
} | |
}); | |
int firstDy = (int) context.getResources().getDimension(R.dimen.fab_menu_firt_dy); | |
int dy = (int) context.getResources().getDimension(R.dimen.fab_menu_dy); | |
for (int i = 0; i < menuItems.size(); i++) { | |
FabMenuItem menuItem = menuItems.get(i); | |
View menuView = View.inflate(context, R.layout.layout_fab_menu_item, null); | |
FloatingActionButton menuFab = menuView.findViewById(R.id.fab); | |
menuFab.setImageResource(menuItem.imageResId); | |
TextView menuFabLabel = menuView.findViewById(R.id.label); | |
menuFabLabel.setText(menuItem.labelResId); | |
menuFabLabel.setAlpha(0f); | |
menuFab.setOnClickListener(new OnClickListenerDelegate(menuItem.action)); | |
int offset = (i + 1) * dy + firstDy; | |
menuItemViews.add(new FabMenuView(offset, menuView, menuFabLabel)); | |
} | |
} | |
private void showFabMenu() { | |
isFabMenuOpened = true; | |
fab.setImageResource(R.drawable.ic_close_primary_vector); | |
maskedView.setPivotX(fab.getX() + fab.getWidth() / 2); | |
maskedView.setPivotY(fab.getY() - fab.getHeight() / 2); | |
parent.addView(maskedView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); | |
CoordinatorLayout.LayoutParams layoutParams = new CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.MATCH_PARENT, CoordinatorLayout.LayoutParams.WRAP_CONTENT); | |
for (FabMenuView menuItemView : menuItemViews) { | |
parent.addView(menuItemView.menuView, layoutParams); | |
menuItemView.menuView.setTranslationY(fab.getY() - fab.getHeight() / 2); | |
menuItemView.menuView.animate().translationY(menuItemView.menuView.getTranslationY() - menuItemView.offsetPx); | |
menuItemView.labelView.animate().setStartDelay(200).setDuration(150).alpha(1f); | |
} | |
maskedView.animate().scaleX(1f).scaleY(1f).alpha(0.85f).setDuration(200); | |
} | |
public void closeFabMenu() { | |
isFabMenuOpened = false; | |
fab.setImageResource(R.drawable.ic_menu_hamburger); | |
for (FabMenuView menuItemView : menuItemViews) { | |
menuItemView.menuView.animate().translationY(fab.getY()); | |
menuItemView.labelView.setAlpha(0f); | |
} | |
maskedView.animate().scaleX(0f).scaleY(0f).setDuration(200).alpha(0f).setListener(animatorListener); | |
} | |
public boolean isOpened() { | |
return isFabMenuOpened; | |
} | |
public void clear() { | |
removeViews(); | |
menuItemViews.clear(); | |
menuItems.clear(); | |
maskedView = null; | |
} | |
private void removeViews() { | |
if (maskedView != null) { | |
parent.removeViewInLayout(maskedView); | |
} | |
for (FabMenuView menuItemView : menuItemViews) { | |
parent.removeViewInLayout(menuItemView.menuView); | |
} | |
} | |
private Animator.AnimatorListener animatorListener = new Animator.AnimatorListener() { | |
@Override | |
public void onAnimationStart(Animator animation) { | |
} | |
@Override | |
public void onAnimationEnd(Animator animation) { | |
if (!isFabMenuOpened) { | |
removeViews(); | |
} | |
} | |
@Override | |
public void onAnimationCancel(Animator animation) { | |
} | |
@Override | |
public void onAnimationRepeat(Animator animation) { | |
} | |
}; | |
class OnClickListenerDelegate implements View.OnClickListener { | |
private final View.OnClickListener clickListener; | |
OnClickListenerDelegate(View.OnClickListener clickListener) { | |
this.clickListener = clickListener; | |
} | |
@Override | |
public void onClick(final View v) { | |
closeFabMenu(); | |
if (clickListener != null) { | |
new Handler().postDelayed(new Runnable() { | |
@Override | |
public void run() { | |
clickListener.onClick(v); | |
} | |
}, 400); | |
} | |
} | |
} | |
public static class FabMenuItem { | |
int imageResId; | |
int labelResId; | |
View.OnClickListener action; | |
FabMenuItem(int imageResId, int labelResId, View.OnClickListener action) { | |
this.imageResId = imageResId; | |
this.labelResId = labelResId; | |
this.action = action; | |
} | |
} | |
public static class FabMenuView { | |
int offsetPx; | |
View menuView; | |
TextView labelView; | |
FabMenuView(int offsetPx, View menuView, TextView labelView) { | |
this.offsetPx = offsetPx; | |
this.menuView = menuView; | |
this.labelView = labelView; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment