Android Bottom Sheet smooth expanding, like Google Maps-ThrowExceptions

Exception or error:

I want to recreate Bottom Sheet Behavior provided in the Google Maps app:

Link to expected behavior.

I have tried using BottomSheetBehavior and couple of other 3rd party libs like umano AndroidSlidingUpPanel but the problem I was unable to avoid is they are all snapping the Bottom Sheet in between states (collapsed and expanded).

I would like to have a Bottom Sheet which can be smoothly expanded by sliding up, without it snapping to the closest state but instead to remain where the user stopped with the sliding.

How to solve:

You can achieve this by subclassing BottomSheetBehavior, and overriding onTouchEvent to return early on ACTION_UP and ACTION_CANCEL.

public class CustomBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

    public CustomBottomSheetBehavior() {
        super();
    }

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

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {

        int action = event.getActionMasked();
        switch (action) {
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                return true;
        }

        return super.onTouchEvent(parent, child, event);
    }
}

This prevents the BottomSheetBehavior class from handling these events and triggering the ‘expand’ or ‘collapse’ call.

To apply your CustomBottomSheetBehavior in xml:
app:layout_behavior="com.yourpackage.CustomBottomSheetBehavior"


To restore default functionality to the BottomSheetBehavior when the sheet is fully expanded or collapsed, you can add a flag which is set when the slide offset reaches a certain value. In the following example, the bottom sheet ACTION_UP and ACTION_CANCEL events are only ignored when the slide offset is between 0.1 and 0.9.

public class CustomBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

    private boolean isExpandedOrCollapsed;

    public CustomBottomSheetBehavior() {
        super();

        listenForSlideEvents();
    }

    public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);

        listenForSlideEvents();
    }

    void listenForSlideEvents() {
        setBottomSheetCallback(new BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {
                isExpandedOrCollapsed = slideOffset < 0.1f || slideOffset > 0.9f;
            }
        });
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {

        if (!isExpandedOrCollapsed) {
            int action = event.getActionMasked();
            switch (action) {
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    return true;
            }
        }

        return super.onTouchEvent(parent, child, event);
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *