Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android onScrollChanged for Scrollview fired multiple times

I want to keep track of the ScrollY on a Scrollview (no, I can't use a grid or a list)

I am using the ViewTreeObserver with an onScrollChanges Listener to it. However, it gets fired multiple times. Even worse: when it gets called 3 of 4 times, the scrollY of the scrollview is 0 and 1 time I get the correct amount. However, it's not like every 4th call is correct, the moment when the correct value is fired is random, and I need to be able to listen to the scrollposition 0.

Here is the Code I use to observer my Scrollview:

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

        @Override
        public void onScrollChanged() {
           Log.d("StupidScrollView", "Scroll positionY: " + mScrollView.getScrollY());
        }
    });

Sample output:

 D/StupidScrollView﹕ Scroll positionY: 0
 D/StupidScrollView﹕ Scroll positionY: 0
 D/StupidScrollView﹕ Scroll positionY: 0
 D/StupidScrollView﹕ Scroll positionY: 77

I have to mention, I am in a ViewPager and my fragments contain a Scrollview which needs to be observed. It somehow sounds like some issue related to that.

like image 995
Angelo Avatar asked Jul 18 '14 13:07

Angelo


1 Answers

I see your problem, i have had a lot of trouble with scrollviews myself.. Here is my solution to get the scrollvalue in a scrollview (I added a System.out for you).

First Create a custom class that extends ScrollView, and create a listener that has the method onScrollChanged as here:

public class ProductDetailScrollView extends ScrollView {

    public interface OnScrollChangedListener {
        void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt);
    }

    private OnScrollChangedListener mOnScrollChangedListener;

    public void setOnScrollChangedListener(OnScrollChangedListener listener) {
        mOnScrollChangedListener = listener;
    }

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

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

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

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

Then i create a variable (in the activity) mOnScrollChangedListener, and set it as the listener for mScrollView:

private ProductDetailScrollView.OnScrollChangedListener mOnScrollChangedListener = new ProductDetailScrollView.OnScrollChangedListener() {
    public void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt) {

        System.out.println("Scrolled: " + t);

        //Parallax Effect on scroll
        if (t > 0) {
            final float newY = (t / 4.0f) * -1.0f;
            mProductImageContainer.setY(newY);
        } else {
            mProductImageContainer.setY(0.0f);
        }
    }
};

The "t" value in my case is how much the scroll have changed vertically, the "l" is the horizontal scroll, and the "oldl" & "oldt" is the old value of t & l so if you need to know that it's scrolled up or down you can use if(oldt > t) etc..

And you set the listener in your scrollview like this:

mScrollView.setOnScrollChangedListener(mOnScrollChangedListener);
like image 100
Ibrahim Yildirim Avatar answered Nov 13 '22 08:11

Ibrahim Yildirim