'Drag and drop gesture from BottomSheetDialogFragment not being handled by View in parent Activity

I'm having a problem with the View I want to drag and drop from the Fragment that is in ViewPager2, which is nested in BottomSheetDialogFragment, not being able to be dragged onto the View that is located in the parent Activity.

The DragListener, which is installed in the CodeView (the View where data is dragged from BottomSheet), simply does not react to the dragged element

override fun initDragNDropListener() {
        binding.fieldLayout.setOnDragListener { _, dragEvent ->
            val draggableItem = dragEvent?.localState as View

            val itemParent = draggableItem.parent as ViewGroup

            when (dragEvent.action) {
                DragEvent.ACTION_DRAG_STARTED,
                DragEvent.ACTION_DRAG_ENTERED,
                DragEvent.ACTION_DRAG_LOCATION,
                DragEvent.ACTION_DRAG_EXITED -> true

                DragEvent.ACTION_DROP -> {
                    handleDropEvent(itemParent, draggableItem, dragEvent)

                    true
                }

                DragEvent.ACTION_DRAG_ENDED -> {
                    draggableItem.post { draggableItem.animate().alpha(1f).duration =
                        UIMoveableCodeBlockInterface.ITEM_APPEAR_ANIMATION_DURATION
                    }

                    this.invalidate()
                    true
                }

                else -> false
            }
        }
    }

private fun handleDropEvent(
        itemParent: ViewGroup,
        draggableItem: View,
        dragEvent: DragEvent
    ) =
        with(binding) {
            val draggableItemWithLastTouchInformation =
                draggableItem as? UICodeBlockWithLastTouchInformation

            draggableItem.x = dragEvent.x - (draggableItem.width / 2)
            draggableItem.y = dragEvent.y - (draggableItem.height / 2)

            draggableItemWithLastTouchInformation?.let {
                draggableItem.x = dragEvent.x - (it.touchX)
                draggableItem.y = dragEvent.y - (it.touchY)
            }

            itemParent.removeView(draggableItem)

            addView(draggableItem)
        }

The drag initializer, which is set to all View that are successfully moved inside the CodeView, looks like this:

interface UIMoveableCodeBlockInterface {
    @SuppressLint("ClickableViewAccessibility")
    fun initDragNDropGesture(view: View, tag: String) {
        view.tag = tag + Random.Default.nextInt().toString()

        var touchX = 0
        var touchY = 0

        view.setOnTouchListener { _, motionEvent ->
            if (motionEvent.actionMasked == MotionEvent.ACTION_DOWN) {
                touchX = motionEvent.x.toInt()
                touchY = motionEvent.y.toInt()
            }

            false
        }

        view.setOnLongClickListener {
            val item = ClipData.Item(tag as? CharSequence)

            val dataToDrag = ClipData(
                tag as? CharSequence,
                arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN),
                item
            )

            (it as? UICodeBlockWithLastTouchInformation)?.setLastTouchInformation(touchX, touchY)

            val maskShadow = BlockDragShadowBuilder(view, touchX, touchY)

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
                @Suppress("DEPRECATION")
                it.startDrag(dataToDrag, maskShadow, this, 0)
            } else {
                it.startDragAndDrop(dataToDrag, maskShadow, this, 0)
            }

            view.animate().alpha(0f).duration = ITEM_DISAPPEAR_ANIMATION_DURATION

            true
        }
    }

    companion object {
        const val ITEM_APPEAR_ANIMATION_DURATION: Long = 400
        const val ITEM_DISAPPEAR_ANIMATION_DURATION: Long = 500
    }
}

The listener that is set for the BottomSheetFragment. Used to hide the BottomBheet in case the dragged View will exceed its limits

override fun initDragNDropListener() {
        binding.viewPager.setOnDragListener { _, dragEvent ->
            val draggableItem = dragEvent?.localState as View

            when (dragEvent.action) {
                DragEvent.ACTION_DRAG_EXITED -> {
                    behaviour.state = BottomSheetBehavior.STATE_HIDDEN

                    val bottomSheetDialog = dialog as BottomSheetDialog

                    bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.container)
                        ?.let {
                            it.visibility = View.GONE
                        }

                    true
                }

                DragEvent.ACTION_DRAG_STARTED,
                DragEvent.ACTION_DRAG_LOCATION,
                DragEvent.ACTION_DRAG_ENTERED,
                DragEvent.ACTION_DRAG_ENDED -> {
                    true
                }

                DragEvent.ACTION_DROP -> {
                    draggableItem.post { draggableItem.visibility = ConstraintLayout.VISIBLE }
                }

                else -> false
            }
        }
    }

In trying to fix what was going on, I thought that some View from BottomSheet was overlapping CodeView, so I used the LayoutInspector to look at the id's that are used to layout BottomSheet and hide them programmatically, but it didn't help

bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.container)
                        ?.let {
                            it.visibility = View.GONE
                        }

layout inspector

Highlighted the element I'm trying to move to fieldLayout

I also tried setting the drag listener to the binding.root of the parent Activity, but that doesn't help either, it doesn't catch any events

Tried calling dismiss(), which also failed

Thank you in advance for your help. I hope there is a solution



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source