0

I'm trying to build a bottomSheetBehavior to allow the user only close the bottomSheet using the drag down gesture. To open it he will click on a button.

So I figure out how he disable drag up/down by this StackOverflow question.

And now I needed to deactivate the drag up gesture only ?

Here is the behavior I created :

class LockedBottomSheetBehavior<V : View>(context: Context, attrs: AttributeSet) :
    BottomSheetBehavior<V>(context, attrs) {

    companion object {
        fun <V : View> from(view: V): LockedBottomSheetBehavior<*> {
            val params = view.layoutParams as? CoordinatorLayout.LayoutParams
                ?: throw IllegalArgumentException("The view is not a child of CoordinatorLayout")
            return params.behavior as? LockedBottomSheetBehavior<*>
                ?: throw IllegalArgumentException(
                    "The view is not associated with BottomSheetBehavior")
        }
    }

    override fun onInterceptTouchEvent(
        parent: CoordinatorLayout,
        child: V, event: MotionEvent
    ) = false

    override fun onTouchEvent(
        parent: CoordinatorLayout,
        child: V,
        event: MotionEvent
    ) = false

    override fun onStartNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        directTargetChild: View,
        target: View,
        axes: Int,
        type: Int) = false

    override fun onNestedPreScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        dx: Int,
        dy: Int,
        consumed: IntArray,
        type: Int) {
    }

    override fun onStopNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        type: Int) {
    }

    override fun onNestedPreFling(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        velocityX: Float,
        velocityY: Float
    ) = false
}

So I added a if statement inside the Behavior to prevent the gesture if it state is collapsed.


override fun onInterceptTouchEvent(
    parent: CoordinatorLayout,
    child: V, event: MotionEvent
): Boolean {
    if (this.state == STATE_EXPANDED) {
        super.onInterceptTouchEvent(parent, child, event)
        return true
    } else {
        return false
    }
}

override fun onTouchEvent(
    parent: CoordinatorLayout,
    child: V,
    event: MotionEvent
): Boolean {
    if (this.state == STATE_EXPANDED) {
        super.onTouchEvent(parent, child, event)
        return true
    } else {
        return false
    }
}

override fun onStartNestedScroll(
    coordinatorLayout: CoordinatorLayout,
    child: V,
    directTargetChild: View,
    target: View,
    axes: Int,
    type: Int): Boolean {
    if (this.state == STATE_DRAGGING) {
        super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type)
        return true
    } else {
        return false
    }


}

override fun onNestedPreScroll(
    coordinatorLayout: CoordinatorLayout,
    child: V,
    target: View,
    dx: Int,
    dy: Int,
    consumed: IntArray,
    type: Int) {
    if (this.state == STATE_DRAGGING) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
    }
}

override fun onStopNestedScroll(
    coordinatorLayout: CoordinatorLayout,
    child: V,
    target: View,
    type: Int) {
    if (this.state == STATE_DRAGGING || this.state == STATE_EXPANDED) {
        super.onStopNestedScroll(coordinatorLayout, child, target, type)
    }
}

override fun onNestedPreFling(
    coordinatorLayout: CoordinatorLayout,
    child: V,
    target: View,
    velocityX: Float,
    velocityY: Float
) = false

But it never reach the dragging gesture.

Zenocode
  • 656
  • 7
  • 19

1 Answers1

1

Following the answer of James Davis

He add a locked var to know if we should activate or not the dragging gesture (in a custom behavior).

class LockedBottomSheetBehavior<V : View>(context: Context, attrs: AttributeSet) :
    BottomSheetBehavior<V>(context, attrs) {

    private var mLocked = true

    fun setLocked(locked: Boolean) {
        mLocked = locked
    }

    override fun onInterceptTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        var handled = false

        if (!mLocked) {
            handled = super.onInterceptTouchEvent(parent, child, event)
        }
        return handled
    }

    override fun onTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        var handled = false

        if (!mLocked) {
            handled = super.onTouchEvent(parent, child, event)
        }
        return handled
    }

    override fun onStartNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        directTargetChild: View,
        target: View,
        axes: Int,
        type: Int) : Boolean {
        var handled = false

        if (!mLocked) {
            handled = super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type)
        }
        return handled
    }

    override fun  onNestedPreScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        dx: Int,
        dy: Int,
        consumed: IntArray,
        type: Int) {
        if (!mLocked) {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
        }
    }

    override fun onStopNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        type: Int) {
        if (!mLocked) {
            super.onStopNestedScroll(coordinatorLayout, child, target, type)
        }
    }

    override fun onNestedPreFling(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
        var handled = false

        if (!mLocked) {
            handled = super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY)
        }
        return handled
    }

}

And then if the state of the bottomSheet change, we activate or not the behavior gesture.

So in my case I wanted to activate the gesture only if the bottomSheet is STATE_EXPANDED and deactivate it when STATE_COLLAPSED.

So here is my version in Kotlin of the bottomSheet behavior to allow user only drag it down, and disable the drag up gesture.

bottomSheetBehavior.setBottomSheetCallback(object: BottomSheetBehavior.BottomSheetCallback() {
    override fun onSlide(bottomSheet: View, slideOffset: Float) {
        Log.d("CAMERA ACTIVITY", "SLIDE, ${this@apply.state}")
    }

    override fun onStateChanged(bottomSheet: View, newState: Int) {
        if (newState == BottomSheetBehavior.STATE_EXPANDED) {
            Log.d("CAMERA ACTIVITY", "STATE CHANGED, ${this@apply.state}")
            (bottomSheetBehavior as LockedBottomSheetBehavior).setLocked(false)
        } else if (newState == BottomSheetBehavior.STATE_COLLAPSED){
            (bottomSheetBehavior as LockedBottomSheetBehavior).setLocked(true)
        }

    }
})
Zenocode
  • 656
  • 7
  • 19