24

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.

superhrvoje
  • 241
  • 2
  • 5

1 Answers1

4

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);
    }
}
Tim Malseed
  • 6,003
  • 6
  • 48
  • 66