15

Im looking for an event that I can use on the scrollView to be fired when the user has scrolled to the bottom.

E.g my list of items should be extended with more items automatically.

Any ideas how this can be done?

I'm thanksfull for any tip.

Vidar Vestnes
  • 41,116
  • 28
  • 81
  • 97

5 Answers5

10

Please read this article: Android: Understanding When Scrollview Has Reached The Bottom

Source code:

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) 
{
    // Grab the last child placed in the ScrollView, we need it to determinate the bottom position.
    View view = (View) getChildAt(getChildCount()-1);

    // Calculate the scrolldiff
    int diff = (view.getBottom()-(getHeight()+getScrollY()));

    // if diff is zero, then the bottom has been reached
    if( diff == 0 )
    {
        // notify that we have reached the bottom
        Log.d(ScrollTest.LOG_TAG, "MyScrollView: Bottom has been reached" );
    }

    super.onScrollChanged(l, t, oldl, oldt);
}

If you want you can add make a custom widget.

Example:

package se.marteinn.ui;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ScrollView;


/**
 * Triggers a event when scrolling reaches bottom.
 *
 * Created by martinsandstrom on 2010-05-12.
 * Updated by martinsandstrom on 2014-07-22.
 *
 * Usage:
 *
 *  scrollView.setOnBottomReachedListener(
 *      new InteractiveScrollView.OnBottomReachedListener() {
 *          @Override
 *          public void onBottomReached() {
 *              // do something
 *          }
 *      }
 *  );
 * 
 *
 * Include in layout:
 *  
 *  <se.marteinn.ui.InteractiveScrollView
 *      android:layout_width="match_parent"
 *      android:layout_height="match_parent" />
 *  
 */
public class InteractiveScrollView extends ScrollView {
    OnBottomReachedListener mListener;

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

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

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

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        View view = (View) getChildAt(getChildCount()-1);
        int diff = (view.getBottom()-(getHeight()+getScrollY()));

        if (diff == 0 && mListener != null) {
            mListener.onBottomReached();
        }

        super.onScrollChanged(l, t, oldl, oldt);
    }


    // Getters & Setters

    public OnBottomReachedListener getOnBottomReachedListener() {
        return mListener;
    }

    public void setOnBottomReachedListener(
            OnBottomReachedListener onBottomReachedListener) {
        mListener = onBottomReachedListener;
    }


    /**
     * Event listener.
     */
    public interface OnBottomReachedListener{
        public void onBottomReached();
    }

}
d.danailov
  • 8,760
  • 4
  • 47
  • 35
  • You can also override onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) and check if clampedY is true – Julian Oct 06 '15 at 21:28
  • I am confused. When you wrote: int diff = (view.getBottom()-(recyclerView.getHeight()+recyclerView.getScrollY())); Why do we need to add recyclerView.getScrollY()? getBottom() calculation is always w.r.t the parent. Why would we need to add the offset? Could you explain please? – Manish Kumar Sharma Aug 20 '16 at 03:28
2

I had the same problem and I solved it by using the ListView (automatically adds ScrollView if needed) and setting OnScrollListener.

Here is a code sample:

        tableListView.setOnScrollListener(new OnScrollListener() {

        public void onScrollStateChanged(AbsListView view, int scrollState) {

        }

        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            if (visibleItemCount == totalItemCount)
            // too little items (ScrollView not needed)
            {
                java.lang.System.out.println("too little items to use a ScrollView!");
            }
            else {
                if ((firstVisibleItem + visibleItemCount) == totalItemCount) {
                    // put your stuff here
                    java.lang.System.out.println("end of the line reached!");
                }
            }

        }
    });
Bojan Kseneman
  • 14,663
  • 2
  • 50
  • 58
0

Don't try SetOnScrollChangeListener if you are working with android API below 21 (android M), you can try this :

yourScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                int rootHeight = yourScrollView.getHeight();
                int childHeight = yourScrollView.getChildAt(0).getHeight();
                int scrollY = yourScrollView.getScrollY();
                if(childHeight - rootHeight == scrollY)
                Log.d("Hei","You Have Reach The End!");
            }
        });
nbsp
  • 2,251
  • 1
  • 14
  • 12
0

It's late for this answer but if anyone stumbles upon, we can do using setOnScrollChangeListener

  childScrollView.setOnScrollChangeListener(object : NestedScrollView.OnScrollChangeListener {
            override fun onScrollChange(v: NestedScrollView?, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) {
                when {//maxScrollPixelPoint  is defined local/global variable
                    scrollY > maxScrollPixelPoint -> {
                        maxScrollPixelPoint = scrollY
                    }
                    scrollY == maxScrollPixelPoint -> {
                        //reached bottom 
                    }
                }
            }

        })
-2

Here is a much simpler solution without having to subclass scroll view. Assuming you have a RecyclerView recyclerView variable,

recyclerView.computeVerticalScrollRange() gives you the complete scroll range, or in other words, the content height.

(recyclerView.computeVerticalScrollOffset() gives the offset from the top as you scroll. This value will go on till the content height - scroll view height.

So,

    if( (recyclerView.computeVerticalScrollOffset() == 
(recyclerView.computeVerticalScrollRange() - recyclerView.getHeight()) ) {
    // You have hit rock bottom.
    }

Manipulating the scroll view's child view just seems so hacky.

Deepak G M
  • 1,593
  • 16
  • 12