5

I'm trying to detect when a ScrollView has finished scrolling so I can slightly modify its position. Before I was using ACTION_UP to detect when the user lifted their finger, but then I realized this wouldn't allow me to use "flinging" as it would modify the scroll before it was finished.

Is there any way to detect when a ScrollView has finished scrolling? Or detect its scroll state like ListView?

Any other ideas on how to implement this?

Thanks.

Steph Sharp
  • 11,462
  • 5
  • 44
  • 81
Matt
  • 2,650
  • 4
  • 36
  • 46
  • Try this link : http://stackoverflow.com/questions/8181828/android-detect-when-scrollview-stops-scrolling – Shraddha May 23 '12 at 05:46

2 Answers2

3

I implemented a solution based on Jourbac comment.

Regards

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ScrollView;

public class MyScrollView extends ScrollView {

    private static final int WHAT = 1;

    class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(!hasMessages(WHAT)) {
                Log.i("TestScroll", "Last msg!. Position from " 
                                    + msg.arg1 + " to " + msg.arg2);                
            }
        }
    }

    private Handler mHandler = new MyHandler();

    public MyScrollView(Context context) {
        super(context);
    }

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

    public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        final Message msg = Message.obtain();
        msg.arg1 = oldt;
        msg.arg2 = t;
        msg.what = WHAT;
        mHandler.sendMessageDelayed(msg, 500);
    }

}
Fede
  • 935
  • 8
  • 14
  • This does not solve what the question maker asked for - it merely sends delayed messages upon every scroll change. – Warlax Apr 21 '11 at 14:25
  • The log message is printed only when the user has finished the scroll in half second. It solves the question. – Fede Apr 28 '11 at 07:32
1

I would approach this by creating a child class of ScrollView, say MyScrollView, and using that instead of ScrollView.

That way you can override the methods of ScrollView which are invoked when scrolling; and add a callback of someform in them (not forgetting to call the corresponding method in super)

I can't really tell you which of ScrollView's methods will be invoked when; I assume one of them is called each time a scoll happens, but which one... maybe simply scrollTo().

I suppose it would be a very interesting and learning experience to override them all and just log when they're called. I might want to do that myself, if I do, I'll be sure to come back with a more useful answer, assuming noone else does during that time.

Joubarc
  • 1,206
  • 10
  • 17
  • Thanks that helps. Is there any place to find the source for ScrollView so I can see how they are handling the scrolling? I suppose I really don't need to change it, just add something onto the end that will handle my stuff, but it would still help to see theirs. – Matt Jun 22 '10 at 19:19
  • Inspecting the source for ScrollView seems a nice idea too indeed. I found the donut version there: http://www.netmite.com/android/mydroid/donut/frameworks/base/core/java/android/widget/ScrollView.java - I see the source for `scrollTo()` has a comment saying that it should be called everytime `scrollBy()` is called - so I would tend to override `scrollTo()` to start with. Good luck with the reading :-) – Joubarc Jun 22 '10 at 19:45
  • 4
    Just override onScrollChanged(). – Romain Guy Jun 22 '10 at 19:51
  • Isn't onScrollChanged part of ListView, not ScrollView? I could be mistaken I've been reading about these so much I keep getting the two confused... If I am mistaken, where would I override it? Joubarc, It seems that I will need to override both scrollTo and fling. Both are used when finger scrolling. Now all I need to figure out just what exactly I need to do to get this to work! This site has been really helpful for me as a novice programmer. Thanks guys! – Matt Jun 22 '10 at 23:11
  • Following up: looks like if I place the code within the overridden Fling and ScrollTo it keeps being called while it is scrolling or flinging, not just at the end. Looks like I either need to find a way to access isFinished (located in scroller.java) or some other way to check if the scrolling is finished... – Matt Jun 23 '10 at 00:10
  • `onScrollChanged()` is a method of View, which is a superclass of both `ScrollView` and `ListView`. Anyway, if Romain says to override that one, just trust him. – Joubarc Jun 23 '10 at 06:20
  • Hmmm, I am still having no luck... Maybe it it working and I just don't know it? Right now from the overridden onScrollChanged, the only code in it is the super and the code for my listener: mOnScrollListener.onScrollFinished(this); where onScrollListener is a public interface in my new view's class. Right now the event is triggering a toast in the main activity. When scrolling/flinging this toast keeps popping up and goes away after a period of inactivity. This leads me to think that it is triggering on every scroll update, not after they are all done. – Matt Jun 23 '10 at 22:33
  • I guess so - and in a way it makes sense; how can it consider when scrolling is truly finished? What if you're just scrolling again immediately after? So if you really need to know, you'll need to implement a timer yourself. Maybe easier with a `Handler` - each time the scroll event triggers, use `PostDelayed` (with for example a delay of 1 second); the runnable you post can simply check if there are more messages in the queue. If there aren't, then no more scrolling event happened in the last second and you can do something different. I'll probably test this myself too when I get some time. – Joubarc Jun 30 '10 at 07:50