Question

I have a scrollview with a lot of content. Now when user do a fling or scroll down, I want the scrollview to stop at a particular view location, where I am doing some animation, and then user can again fling or scroll down.

I have tried the disabling of scrollview as mentioned here but It only disables when the scrollview completely stops and cannot stop in the middle of a fling.

Is there any way I can stop a fling of the scrollview when a certain view location or a certain y value is reached?

Was it helpful?

Solution

I had the same problem my solution was.

listView.smoothScrollBy(0,0)

This will stop the scrolling.

OTHER TIPS

To stop a fling at a particular point simply call

fling(0)

If you are only concerned about flings this is the most logical way to do so in my opinion, because velosityYis set to 0 and thereby the fling is stopped immediately.

Here is the javadoc of the fling method:

/**
 * Fling the scroll view
 *
 * @param velocityY The initial velocity in the Y direction. Positive
 *                  numbers mean that the finger/cursor is moving down the screen,
 *                  which means we want to scroll towards the top.
 */

One approach may be to use smoothScrollToPosition, which stops any existing scrolling motion. Note this method requires API level >= 8 (Android 2.2, Froyo).

Note that if the current position is far away from the desired position, then the smooth scrolling will take quite a long time and look a bit jerky (at least in my testing on Android 4.4 KitKat). I also found that a combination of calling setSelection and smoothScrollToPosition could sometimes causes the position to "miss" slightly, this seems to happen only when the current position was very close to the desired position.

In my case, I wanted my list to jump to the top (position=0) when the user pressed a button (this is slightly different from your use case, so you will need to adapt this to your needs).

I used the following method to

private void smartScrollToPosition(ListView listView, int desiredPosition) {
    // If we are far away from the desired position, jump closer and then smooth scroll
    // Note: we implement this ourselves because smoothScrollToPositionFromTop
    // requires API 11, and it is slow and janky if the scroll distance is large,
    // and smoothScrollToPosition takes too long if the scroll distance is large.
    // Jumping close and scrolling the remaining distance gives a good compromise.
    int currentPosition = listView.getFirstVisiblePosition();
    int maxScrollDistance = 10;
    if (currentPosition - desiredPosition >= maxScrollDistance) {
        listView.setSelection(desiredPosition + maxScrollDistance);
    } else if (desiredPosition - currentPosition >= maxScrollDistance) {
        listView.setSelection(desiredPosition - maxScrollDistance);
    }
    listView.smoothScrollToPosition(desiredPosition); // requires API 8
}

In my action handler for the button I then called this as follows

    case R.id.action_go_to_today:
        ListView listView = (ListView) findViewById(R.id.lessonsListView);
        smartScrollToPosition(listView, 0); // scroll to top
        return true;

The above does not directly answer your question, but if you can detect when the current position is at or near your desired position, then maybe you could use smoothScrollToPosition to stop the scrolling.

You need to disable ScrollView handling of the fling operation. To do this simply override the fling method in ScrollView and comment super.fling(). Let me know if this works !

public class CustomScrollView extends ScrollView {

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
    {
    return false;
    }

    @Override
    public void fling (int velocityY)
    {
    /*Scroll view is no longer gonna handle scroll velocity.
    * super.fling(velocityY);
     */
    }
 }

I'm trying to achieve a similar situation. I have a partial solution:

I've managed to stop the ScrollView at a particular y coordinate by overriding onScrollChanged and then calling smoothScrollTo. I allow the user to continue scrolling down past that point by keeping a boolean that indicates if this was the first fling/drag or not. And the same goes for scrolling from bottom to top - I stop the scroll at the same point again. And then allow the user to continue scrolling upward again.

The code looks something like this:

boolean beenThereFromTop = false;
boolean beenThereFromBottom = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);

    scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {

        @Override
        public void onScrollChanged() {

            TextView whereToStop = (TextView) findViewById(R.id.whereToStop);
            final int y = whereToStop.getBottom();

            int scrollY = scrollView.getScrollY();

// manage scrolling from top to bottom

            if (scrollY > y) {
                if (!beenThereFromTop) {
                    beenThereFromTop = true;
                    scrollView.post(new Runnable() {
                        @Override
                        public void run() {
                            scrollView.smoothScrollTo(0, y);
                        }
                    });
                }
            }
            if (scrollY < y && beenThereFromTop) {
                beenThereFromTop = false;
            }

// manage scrolling from bottom to top

            if (scrollY < y) {
                if (!beenThereFromBottom) {
                    beenThereFromBottom = true;
                    scrollView.post(new Runnable() {
                        @Override
                        public void run() {
                            scrollView.smoothScrollTo(0, y);
                        }
                    });
                }
            }
            if (scrollY > y && beenThereFromBottom) {
                beenThereFromBottom = false;
            }
        }
    });
}

Well im actualy using this method:

 list.post(new Runnable() 
                        {
                            @Override
                            public void run() 
                            {
                               list.smoothScrollToPositionFromTop(arg2, 150); 
                            }
                        });
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top