Skip to content

Instantly share code, notes, and snippets.

@Subtle-fox
Created March 6, 2018 12:38
Show Gist options
  • Save Subtle-fox/b952c4c0eb8b43e063c8be329bc3dcaf to your computer and use it in GitHub Desktop.
Save Subtle-fox/b952c4c0eb8b43e063c8be329bc3dcaf to your computer and use it in GitHub Desktop.
"Floating Action Button" menu
/**
* 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