Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a scrollView autoscroll with drag and drop in Android

I searched all over, but could not find a solution.

I have a view (lets call it myView) inside a scrollview. myView is bigger than the screen. Since I'm able to get the relative x,y position of my finger inside myView, I would like to make the scrollView autoscroll to the top/bottom when my finger enters a certain top/bottom threshold. I have some ideas, namely translating the drag location to the screen position but this did not solve this problem.

thanks in advance

cheers

like image 421
thehayro Avatar asked Sep 08 '11 17:09

thehayro


People also ask

What is the difference between NestedScrollView and ScrollView?

NestedScrollView is just like ScrollView , but it supports acting as both a nested scrolling parent and child on both new and old versions of Android. Nested scrolling is enabled by default.

What is fillViewport in ScrollView?

android:fillViewport. Defines whether the scrollview should stretch its content to fill the viewport.


2 Answers

All right I figured it out by myself.

First I had to extend the ScrollView class and added an interface OnScrollViewListener.

public class MyScrollView extends ScrollView {
    private OnScrollViewListener mListener;

    public MyScrollView(Context c, AttributeSet attrs) {
       super(c, attrs);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
       super.onScrollChanged(l, t, oldl, oldt);
       if (mListener != null) {
           mListener.onScrollChanged((OnScrollViewListener) this);
       }
    }


    public void setOnScrollViewListener(OnScrollViewListener listener) {
       mListener = listener;
    }


    public static interface OnScrollViewListener {
       public void onScrollChanged(OnScrollViewListener listener);
    }
}

Next in my Activity I inserted a member mScrollDistance that indicates the amount of pixels the user scrolls.

public class ScrollActivity extends Activity {
   private int mScrollDistance;

   @Override
   protected void OnCreate(...) {
     ...

     final MyScrollView myScrollView = (MyScrollView) findViewById(R.id.scroll_view);
     myScrollView.setOnScrollViewListener(new MyScrollView.OnScrollViewListener() {

          public void onScrollChanged(OnScrollViewListener listener) {
             mScrollDistance = listener.getScrollY();
          }
     }

     // making an drag and drop in an view that is inside the MyScrollView
     final LinearLayout myLayout = (LinearLayout)findViewById(R.id.linear_layout);
     myLayout.setOnDragListener(new View.OnDragListener() {
       public boolean onDrag (View v, DragEvent event) {
         int action = event.getAction();
         switch(action) {
            case DragEvent.ACTION_DRAG_STARTED: {
            }
            case DragEvent.ACTION_DRAG_LOCATION: {

              int y = Math.round(event.getY());
              int translatedY = y - mScrollDistance;
              int threshold = 50;
              // make a scrolling up due the y has passed the threshold
              if (translatedY < threshold) {
                 // make a scroll up by 30 px
                 myScrollView.scrollBy(0, -30);
              }
              // make a autoscrolling down due y has passed the 500 px border
              if (translatedY + threshold > 500) {
                 // make a scroll down by 30 px
                 myScrollView.scrollBy(0, 30);
              }
              // listen for more actions here
              // ...
            }
         }
       }
     }

Now, mScrollDistance gets always a new value and the drag location will be translated to the view location. I tested this and it works on layouts/views that are bigger than the screen size.

Hope that helps.

like image 182
thehayro Avatar answered Oct 03 '22 12:10

thehayro


I came up with a different solution and I am happy with it.

I want to be able to drag and drop views inside a ScrollView. The ScrollView then needs to scroll up and down automatically when the shadow reaches the edges of the scroll view.

I ended up with a solution that detects wether the drop zone is completely visible inside the scrollview (with a 100px margin) and adjust the scroll view otherwise.

@Override
public boolean onDrag(View view, DragEvent event) {

    MainWidget dropZoneView = (MainWidget) view;

    int action = event.getAction();
    switch (action) {
        case DragEvent.ACTION_DRAG_STARTED:
        //(... other stuff happens here)
        case DragEvent.ACTION_DRAG_LOCATION:

            ScrollView mainScrollView = (ScrollView) findViewById(R.id.main_scroll);

            int topOfDropZone = dropZoneView.getTop();
            int bottomOfDropZone = dropZoneView.getBottom();

            int scrollY = mainScrollView.getScrollY();
            int scrollViewHeight = mainScrollView.getMeasuredHeight();

            Log.d(LOG_TAG,"location: Scroll Y: "+ scrollY + " Scroll Y+Height: "+(scrollY + scrollViewHeight));
            Log.d(LOG_TAG," top: "+ topOfDropZone +" bottom: "+bottomOfDropZone);

            if (bottomOfDropZone > (scrollY + scrollViewHeight - 100))
                mainScrollView.smoothScrollBy(0, 30);

            if (topOfDropZone < (scrollY + 100))
                mainScrollView.smoothScrollBy(0, -30);

            break;
        default:
            break;
    }
    return true;
}

Hope this helps!

like image 30
Tiago A. Avatar answered Oct 03 '22 11:10

Tiago A.