Skip to content

Instantly share code, notes, and snippets.

@Subtle-fox
Created March 6, 2018 12:38

Revisions

  1. Subtle-fox created this gist Mar 6, 2018.
    208 changes: 208 additions & 0 deletions FabMenu.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,208 @@
    /**
    * 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;
    }
    }
    }