'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
}
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 |
|---|

