Как обнаружить прокрутку веб-просмотра в Android?

У меня есть нативное приложение, в котором я хочу показать / скрыть кнопку, если пользователь прокручивает страницу до конца. Я посмотрел на ответ здесь и получил полное представление о том, как зарегистрировать обратный вызов через интерфейс. Моя главная проблема заключается в том, что я не могу получить свои расчеты прямо в методе onScrollChanged. Я пробовал сочетание таких вещей, как getHeight(), getContentHeight(), top и т. Д., Но кажется, что он срабатывает слишком рано. Я пробовал на простой странице, такой как Google, со сравнительно меньшим содержанием, а также на странице новостей.

Эти логики работают нормально для обычного просмотра прокрутки. Поскольку на веб-странице много контента, это может привести к ошибкам в расчетах. Вставка примера кода: не работает.

@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);
}

Нужна помощь с этим. Благодарю.

7 ответов

@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);
}

Эта логика прекрасно работает для веб-просмотра.

После большого количества поисков в Google все решения, которые я нашел, вычисляли высоту и определяли scrollOfset, но большинство из них не являются надежными в большинстве случаев, приводя к проблемам, подобным описанным здесь. Странный просчет при попытке определить, прокручивается ли WebView до дна

Я нашел решение, которое работает на 100%, чтобы определить его на основе 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
                        }

                }
            });

Во-первых, расширьте свое веб-представление из этого класса. /questions/333523/kak-sdelat-scroll-listener-dlya-webview-v-android/333533#333533 После этого обновите свой веб-сайт.

 <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" />

И, наконец, переопределите метод onScroll следующим образом:

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();


            }
        });

Проверял на андроид версии 8-11. работает на 100%. Я добился этого с помощью computeVerticalScrollRange и computeVerticalScrollExtent.Following - это пример веб-просмотра внутри активности / фрагмента.

Создайте собственный класс веб-просмотра.

      public class MyWebView extends WebView {
    public MyWebView(Context context) {
        super(context);
    }

    public MyWebView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public int computeVerticalScrollRange() {
        return super.computeVerticalScrollRange();
    }

    @Override
    protected int computeVerticalScrollExtent() {
        return super.computeVerticalScrollExtent();
    }
}

В своем файле макета реализуйте веб-просмотр, подобный этому, и включите этот файл макета в свой файл действия или фрагментного представления, если вам нужно.

       <in.package.folder.MyWebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="0dp"/>

В вашей деятельности / фрагменте, где вы хотите иметь веб-просмотр

  1. объявить переменную
      private MyWebView webView;
  1. найти идентификатор элемента и инициализировать webView
       webView = (MyWebView) findViewById(R.id.webview);
  1. Используйте методы computeVerticalScrollRange и computeVerticalScrollExtent, определенные в классе webview, для вычисления конца прокрутки. 3-й параметр i1 (Прокрутка Y) будет равен (computeVerticalScrollRange - computeVerticalScrollExtent), если прокрутка достигла конца содержимого веб-просмотра.
       webView.setOnScrollChangeListener((view, i, i1, i2, i3) -> {
            int r1 = webView.computeVerticalScrollRange();
            int r2 = webView.computeVerticalScrollExtent();
            if (i1 == (r1 - r2)) {
                "REACHED END OF THE SCROLL"
            } 
        });

Эта комбинация из трех методов отлично работает для меня

  1. Создайте две логические переменные: два обнаружения topReached или bottomReached.

  2. используйте computeVerticalScrollRange(), чтобы получить диапазон вертикальной прокрутки. computeVerticalScrollRange() поможет вам, когда высота содержимого меньше (в таком случае onScrollChanged не вызывается).

  3. используйте onScrollChanged, чтобы обнаружить, что прокрутка происходит. прокрутка происходит случайно, значит высота содержимого больше измеренной высоты webView. Теперь можно определить нижний конец, используя newt, или определить верхний, используя 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);

}

Может немного опоздать на вечеринку:

          enum class ScrollDirection(val direction: Int) {
        Upwards(-1),
        Downwards(1)
    }
        
     private fun detectOnScrollMaxDown() = with(binding) {
            webView.setOnScrollChangeListener { _, _, _, _, _ ->
                val isDownDirectPossible = webView.canScrollVertically(ScrollDirection.Downwards.direction)
                if (!isDownDirectPossible) Log.d("Reached the bottom? ","${!isDownDirectPossible}")
            }
        }

У меня работают следующие коды Kotlin:

          web_view.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
        val measuredHeight: Int = web_view.measuredHeight
        if(measuredHeight + scrollY == web_view.computeVerticalScrollRange()){
            Log.d("WebView","Reach bottom")
        }
    }

Протестировано для Android 12 и Android 10. Уровень API 31.

Другие вопросы по тегам