Reputation: 1123
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?
Upvotes: 15
Views: 17044
Reputation: 4289
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 velosityY
is 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.
*/
Upvotes: 8
Reputation: 3866
I had the same problem my solution was.
listView.smoothScrollBy(0,0)
This will stop the scrolling.
Upvotes: 16
Reputation: 2444
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;
}
}
});
}
Upvotes: 1
Reputation: 1732
Well im actualy using this method:
list.post(new Runnable()
{
@Override
public void run()
{
list.smoothScrollToPositionFromTop(arg2, 150);
}
});
Upvotes: 0
Reputation: 106
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.
Upvotes: 4
Reputation: 17264
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);
*/
}
}
Upvotes: 1