11

Mine is a native app where I want to show/ hide a button if the user scrolls to the end of webview. I looked at an answer here and got the entire idea of how to register the callback via interface. My major issue is that I am not able to get my calculations right inside the onScrollChanged method. I have tried combination of things like getHeight(), getContentHeight(), top etc but it just seems to fire too early. I tried with a simple page like google's with comparatively lesser content as well as a news page.

These logics work fine for a normal scroll view. Since the webpage has a lot of content, it could be messing up the calculations. Pasting a sample code: does not work.

@Override
protected void onScrollChanged(int left, int top, int oldLeft, int oldTop) {
    if ( mOnWebViewBottomReachedListener != null ) {
        //if ( (getContentHeight() - (top + getHeight())) <= mMinDistance )
        int diff = (getBottom() - (getHeight() + getScrollY()));
        Log.e("values ", diff+" o");
        if ((int) Math.floor(getContentHeight() * getScaleY()) == top)
            mOnWebViewBottomReachedListener.onBottomReached(this);
    }
    super.onScrollChanged(left, top, oldLeft, oldTop);
}

Need help with this. Thanks.

Community
  • 1
  • 1
Rajat Sharma
  • 436
  • 3
  • 7
  • 17
  • dupe of http://stackoverflow.com/questions/20513141/weird-miscalculation-when-trying-to-detect-if-webview-scrolled-to-bottom ? – marcin.kosiba Jan 10 '14 at 11:44

4 Answers4

14
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    int height = (int) Math.floor(this.getContentHeight() * this.getScale());  
    int webViewHeight = this.getMeasuredHeight();  
    if(this.getScrollY() + webViewHeight >= height){  
       Log.i("THE END", "reached");
    }
    super.onScrollChanged(l, t, oldl, oldt);
}

This logic works fine for a webview.

PhilLab
  • 4,430
  • 19
  • 63
Swati Sachdeva
  • 233
  • 2
  • 11
  • 1
    nice try. but not works perfect because web view gives getContentHeight() of older web page when new page just loaded. – Abhishek Aug 05 '17 at 08:10
  • Just changed this.getScale() by newScale & get newScale in onScaleChanged method.Check more detail in https://developer.android.com/reference/android/webkit/WebViewClient.html#onScaleChanged(android.webkit.WebView,%20float,%20float) – Rajan Kashiyani Mar 16 '19 at 10:40
  • Worked for me when I changed getScale()(deprecated) to getScaleY(). I was trying to detect scroll to bottom. – ChinLoong Oct 07 '19 at 03:06
11

After a lot of google search all the solutions I found were calculating the height and determining the scrollOfset, but most of them are not reliable in most cases resulting in issues like described here Weird miscalculation when trying to detect if WebView scrolled to bottom

I have found the solution that works 100% is to determine it based on overScroll

webView.setOnOverScrolledCallback(new WebViewCustom.OnOverScrolledCallback() {
                @Override
                public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
                    if(clampedY)
                        if(scrollY == 0) {
                            //top
                        }
                        else {
                            //bottom
                        }

                }
            });
Community
  • 1
  • 1
Aurel Nica
  • 111
  • 1
  • 2
  • 2
    Nice method. Thank you. I think, It will be useful for Android newbies to see a more detailed code fragment. Just add some note, e.g. WebView component should be extended by setOnOverScrolledCallback like it is demonstrated here http://qaru.site/questions/15337126/webview-in-nestedscrollview-scrolling – Ayaz Alifov Aug 25 '19 at 19:27
  • This worked for me after searching through a lot of comments in stackoverflow. thanks! – Vivek Jayakumar Mar 16 '20 at 17:28
4

Firstly extend your webview from this class. https://stackoverflow.com/a/14753235/3027225 After this upgrade your webView like this

 <com.YourPackageName.ObservableWebView
            android:id="@+id/webView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentRight="true" />

And finally override the onScroll method like the following:

webView.setOnScrollChangedCallback(new OnScrollChangedCallback() {

            @Override
            public void onScroll(int l, int t) {
                  int tek = (int) Math.floor(webView.getContentHeight() * webView.getScale());
                  if(tek - webView.getScrollY() == webView.getHeight())
                     Toast.makeText(getActivity(), "End", Toast.LENGTH_SHORT).show();


            }
        });
Community
  • 1
  • 1
Cüneyt
  • 2,678
  • 25
  • 31
2

This three method combination work excellent for me

  1. Create two boolean variable two detect topReached or bottomReached.

  2. use computeVerticalScrollRange() to get vertical scroll range. computeVerticalScrollRange() will help you when content height is less(In such case onScrollChanged not called).

  3. use onScrollChanged to detect scrolling is happing. scrolling is happing means content height is greater than webView measured height.Now detect bottom end using newt or detect top using newt.
private boolean topReached = false, bottomReached = false;

 @Override
protected int computeVerticalScrollRange() {

    int readerViewHeight = getMeasuredHeight();

    int verticalScrollRange = super.computeVerticalScrollRange();


    if (readerViewHeight >= verticalScrollRange) {

        topReached = true;

        bottomReached = true;

    }

    return verticalScrollRange;
}

@Override
protected void onScrollChanged(int newLeft, int newTop, int oldLeft, int oldTop) {

    Logger.i(TAG, "onScrollChanged");

    topReached = false;

    bottomReached = false;

    Log.i(TAG, "onScrollChanged newLeft : " + newLeft);
    Log.i(TAG, "onScrollChanged newTop : " + newTop);
    Log.i(TAG, "onScrollChanged oldLeft : " + oldLeft);
    Log.i(TAG, "onScrollChanged oldTop : " + oldTop);

    int readerViewHeight = getMeasuredHeight();

    int contentHeight = getContentHeight();

    if (newTop == 0) {

        Log.d(TAG, "onScrollChanged : Top End");

        topReached = true;

    } else if (newTop + readerViewHeight >= contentHeight) {

        Log.d(TAG, "onScrollChanged : Bottom End");

        bottomReached = true;

    }

    super.onScrollChanged(newLeft, newTop, oldLeft, oldTop);

}
Abhishek
  • 3,156
  • 2
  • 14
  • 28