Android: How to detect when a scroll has ended

Viewed 59375

I am using the onScroll method of GestureDetector.SimpleOnGestureListener to scroll a large bitmap on a canvas. When the scroll has ended I want to redraw the bitmap in case the user wants to scroll further ... off the edge of the bitmap, but I can't see how to detect when the scroll has ended (the user has lifted his finger from the screen).

e2.getAction() always seems to return the value 2 so that is no help. e2.getPressure seems to return fairly constant values (around 0.25) until the final onScroll call when the pressure seems to fall to about 0.13. I suppose I could detect this reduction in pressure, but this will be far from foolproof.

There must be a better way: can anyone help, please?

14 Answers

You should take a look at http://developer.android.com/reference/android/widget/Scroller.html. Especially this could be of help (sorted by relevance):

isFinished();
computeScrollOffset();
getFinalY(); getFinalX(); and getCurrY() getCurrX()
getDuration()

This implies that you have to create a Scroller.

If you want to use touching you could also use GestureDetector and define your own canvas scrolling. The following sample is creating a ScrollableImageView and in order to use it, you have to define the measurements of your image. You can define your own scrolling range and after finishing your scrolling the image gets redrawn.

http://www.anddev.org/viewtopic.php?p=31487#31487

Depending on your code you should consider invalidating (int l, int t, int r, int b); for the invalidation.

I am sure it is too late for you, however, it seems I have found the right solution to your original question and not necessarily the intention.

If you are using Scroller/OverScroller Object for scrolling you should check the return value from the following function.

public boolean computeScrollOffset() 

I haven't done this myself but looking at onTouch() you always get a sequence 0<2>1, so the end has to be a 1 for finger lift.

I don't know Android, but looking at the documentation it seems Rob is right: Android ACTION_UP constant Try checking for ACTION_UP from getAction()?

Edit: What does e1.getAction() show? Does it ever return ACTION_UP? The documentation says it holds the initial down event, so maybe it'll also notify when the pointer is up

Edit: Only two more things I can think of. Are you returning false at any point? That may prevent ACTION_UP

The only other thing I'd try is to have a seperate event, maybe onDown, and set a flag within onScroll such as isScrolling. When ACTION_UP is given to onDown and isScrolling is set then you could do whatever you want and reset isScrolling to false. That is, assuming onDown gets called along with onScroll, and getAction will return ACTION_UP during onDown

i have not tried / used this but an idea for an approach:

stop / interrupt redrawing canvas on EVERY scroll event wait 1s and then start redrawing canvas on EVERY scroll.

this will lead to performing the redraw only at scroll end as only the last scroll will actually be uninterrupted for the redraw to complete.

hope this idea helps you :)

Extract from the onScroll event from GestureListener API: link text

public abstract boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) Since: API Level 1

Returns * true if the event is consumed, else false

Perhaps once the event has been consumed, the action is finished and the user has taken their finger off the screen or at the least finished this onScroll action

You can then use this in an IF statement to scan for == true and then commence with the next action.

My attempt at adding additional functionality to the gesture detector. Hope it helps someone put his time to better use... gist

If you're using SimpleGestureDetector to handle your scroll events, you can do this

fun handleTouchEvents(event: MotionEvent): Boolean {
    if(event.action == ACTION_UP) yourListener.onScrollEnd()
    return gestureDetector.onTouchEvent(event)
}
Related