Search code examples
androidonclicklistenerfloating-action-button

How to create a custom click listener on floating action button


How do I create a custom click listener on FAB or use the return performClick()?

I have been trying to get android floating button to respond to click but it doesn't work on my custom click event, I have also tried passing the custom click while initializing the class with no luck. Please what am I missing?

import com.google.android.material.floatingactionbutton.FloatingActionButton;

public class MovableFloatingActionButton extends FloatingActionButton implements View.OnTouchListener {

    private final static float CLICK_DRAG_TOLERANCE = 10; // Often, there will be a slight, unintentional, drag when the user taps the FAB, so we need to account for this.

    private float downRawX, downRawY;
    private float dX, dY;
    CustomClickListener customClickListener;

    public MovableFloatingActionButton(Context context) {
        super(context);
        init();
    }

    public MovableFloatingActionButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MovableFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent){

        ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)view.getLayoutParams();

        int action = motionEvent.getAction();
        if (action == MotionEvent.ACTION_DOWN) {

            downRawX = motionEvent.getRawX();
            downRawY = motionEvent.getRawY();
            dX = view.getX() - downRawX;
            dY = view.getY() - downRawY;

            return true; // Consumed

        }
        else if (action == MotionEvent.ACTION_MOVE) {

            int viewWidth = view.getWidth();
            int viewHeight = view.getHeight();

            View viewParent = (View)view.getParent();
            int parentWidth = viewParent.getWidth();
            int parentHeight = viewParent.getHeight();

            float newX = motionEvent.getRawX() + dX;
            newX = Math.max(layoutParams.leftMargin, newX); // Don't allow the FAB past the left hand side of the parent
            newX = Math.min(parentWidth - viewWidth - layoutParams.rightMargin, newX); // Don't allow the FAB past the right hand side of the parent

            float newY = motionEvent.getRawY() + dY;
            newY = Math.max(layoutParams.topMargin, newY); // Don't allow the FAB past the top of the parent
            newY = Math.min(parentHeight - viewHeight - layoutParams.bottomMargin, newY); // Don't allow the FAB past the bottom of the parent

            view.animate()
                    .x(newX)
                    .y(newY)
                    .setDuration(0)
                    .start();

            return true; // Consumed

        }
        else if (action == MotionEvent.ACTION_UP) {

            float upRawX = motionEvent.getRawX();
            float upRawY = motionEvent.getRawY();

            float upDX = upRawX - downRawX;
            float upDY = upRawY - downRawY;

            if (Math.abs(upDX) < CLICK_DRAG_TOLERANCE && Math.abs(upDY) < CLICK_DRAG_TOLERANCE) { // A click
                if (customClickListener != null) {
                    customClickListener.onClick(view);
                }
                return false;
                //return performClick();
            }
            else { // A drag
                return true; // Consumed
            }

        }
        else {
            return super.onTouchEvent(motionEvent);
        }

    }

    public void setCustomClickListener(CustomClickListener customClickListener) {
        this.customClickListener = customClickListener;
    }

    public interface CustomClickListener {
        void onClick(View view);
    }
}

This is how I use the class on main activity

   MovableFloatingActionButton fl = new MovableFloatingActionButton(this);
    fl.setCustomClickListener(new MovableFloatingActionButton.CustomClickListener() {
        @Override
        public void onClick(View view) {
            Log.e("FAB", "Float Clicked");
        }
    });

Solution

  • Perform click will not work in this case, because you have created your custom click listener, so whenever you use performClick(), callback of setOnClickListener will be executed. But you are using CustomClickListener.

    So as solution you have to create other method for performing your click for CustomClickListener.

    Inside your class MovableFloatingActionButton just add this method:

    public void customClick() {
        if (customClickListener != null) {
            customClickListener.onClick(this);
        }
    }
    

    and than use this method to execute code.

    Another thing to consider is, You have following code.

    MovableFloatingActionButton fl = new MovableFloatingActionButton(this);
    

    If you are dynamically using this Floating button and adding it to your views dynamically than no change require.

    But if you are using inside xml file and access in Java file than you have to use like this:

    MovableFloatingActionButton fl= findViewById(R.id.mov);
    

    and later you can use fl.customClick() to execute your custom click listener.