Search code examples
androidkotlinscrolldrag-and-dropscrollview

Scroll while dragging


I have some TextViews with drag and drop implemented in Kotlin and I what I would like to do is when I drag one TextView at the bottom of the screen, where a ScrollView is located, for it to scroll downwards.

Here is the app design.

As it is shown in the image, I want to drag TextViews from the left column (components) and drop then into the right column (boxes). The boxes LinearLayout continues off screen, and the point is that I don't want the user to have to scroll to the last box before dragging something into it from the "components" LinearLayout.


Solution

  • So to answer my own question, the solution i found is this:

    lowerLimForScroll = (Resources.getSystem().displayMetrics.heightPixels * 0.8).toInt()
    
    textView.setOnDragListener { boxContentView, dragEvent -> 
                
        val boxesLayoutCoords = intArrayOf(0, 0)
        // this calculates the x, y of the top left corner of the 
        // ScrollView
        boxContentView.getLocationInWindow(boxesLayoutCoords)
        when (dragEvent.action) {
            DragEvent.ACTION_DRAG_LOCATION -> {
                checkForScroll(dragEvent.y, boxesLayoutCoords[1])
        }
        true
    }
    

    likewise, i have to do add an on Drag Listener to the scrollView as well because i use dividers and the scrolling stopped when i got out of the scrollview and hovered over the divider which belongs to the ScrollView

    scrollView.setOnDragListener { _, dragEvent ->
    
        val boxesLayoutCoords = intArrayOf(0, 0)
        scrollView.getLocationInWindow(boxesLayoutCoords)
    
        when (dragEvent.action) {
            DragEvent.ACTION_DRAG_LOCATION -> {
                checkForScroll(dragEvent.y, boxesLayoutCoords[1])
            }              
        }
        true
    }
    

    and finally the checkForScroll function

    private fun checkForScroll(pointerY: Float, startOfScrollView: Int) {
        /* if the upper limit is passed, meaning a pixel height, scroll up */
        if ((pointerY + startOfScrollView) < upperLimForScroll) {
            findViewById<ScrollView>(R.id.boxesScrollView).smoothScrollBy(0, -20)
        }
        /* if the lower limit is passed, meaning a pixel height, scroll down */
        else if (pointerY + startOfScrollView > lowerLimForScroll) {
            findViewById<ScrollView>(R.id.boxesScrollView).smoothScrollBy(0, 15)
        }
    }