Вопрос по android – Определить конец ScrollView

61

У меня есть приложение, которое имеет активность, которая используетScrollView, Мне нужно определить, когда пользователь добирается до нижней частиScrollView, Я немного погуглил и нашелэта страница где объясняется Но, в примере, что ребята расширяетScrollView, Как я уже сказал, мне нужно расширить активность.

Итак, я сказал "хорошо, давайте попробуем сделать расширение собственного классаScrollViewпереопределитьonScrollChanged() метод, определить конец прокрутки и действовать соответственно ".

Я сделал, но в этой строке:

scroll = (ScrollViewExt) findViewById(R.id.scrollView1);

это бросаетjava.lang.ClassCastException, Я изменил<ScrollView> теги в моем XML, но, очевидно, это не работает. Мои вопросы: почему, еслиScrollViewExt продолжаетсяScrollViewбросает мне в лицоClassCastException? Есть ли способ обнаружить конец прокрутки, не путая слишком много?

Спасибо, люди.

РЕДАКТИРОВАТЬ: Как и было обещано, вот часть моего XML, которая имеет значение:

<ScrollView
        android:id="@+id/scrollView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >


        <WebView
            android:id="@+id/textterms"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_horizontal"
            android:textColor="@android:color/black" />

    </ScrollView>

Я изменил это сTextView вWebView чтобы быть в состоянии оправдать текст внутри. Чего я хочу добиться, так это того, что кнопка «Принять» не активируется до тех пор, пока условия контракта не будут полностью прочитаны ». вещь. Мой расширенный класс называетсяScrollViewExт. Если я изменю тегScrollView заScrollViewExt это бросает

android.view.InflateException: Binary XML file line #44: Error inflating class ScrollViewExt

потому что он не понимает тегScrollViewEx, Я не думаю, что у него есть решение ...

Спасибо за ваши ответы!

Нет необходимости в пользовательских классах или сложных расширениях. Просто используйтеcanScrollVertically(int) yuval
покажи нам свой макет xml Renard

Ваш Ответ

10   ответов
18

но есть простой встроенный метод, который выполняет это:canScrollVertically(int)

Например:

@Override
public void onScrollChanged() {
    if (!scrollView.canScrollVertically(1)) {
        // bottom of scroll view
    }
    if (!scrollView.canScrollVertically(-1)) {
        // top of scroll view
    }
}

Это также работает с RecyclerView, ListView и фактически любым другим представлением, так как метод реализован наView.

Если у вас есть горизонтальный ScrollView, то же самое может быть достигнуто сcanScrollHorizontally(int)

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
10

EDIT

С содержанием вашего XML, я вижу, что вы используете ScrollView. Если вы хотите использовать свой пользовательский вид, вы должны написать com.your.packagename.ScrollViewExt, и вы сможете использовать его в своем коде.

<com.your.packagename.ScrollViewExt
    android:id="@+id/scrollView1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <WebView
        android:id="@+id/textterms"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:textColor="@android:color/black" />

</com.your.packagename.ScrollViewExt>

EDIT END

Не могли бы вы опубликовать содержание XML?

Я думаю, что вы могли бы просто добавить прослушиватель прокрутки и проверить, является ли последний показанный элемент самым последним из списка, например:

mListView.setOnScrollListener(new OnScrollListener() {      
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub      
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        // TODO Auto-generated method stub
        if(view.getLastVisiblePosition()==(totalItemCount-1)){
            //dosomething
        }
    }
});
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Fustigador
1

ScrollView Вы также можете использовать переменную-член и сохранить последнюю y-позицию. Затем вы можете сравнить последнюю y-позицию с текущей позицией прокрутки.

private int scrollViewPos;

...

@Override
public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) {

   //reached end of scrollview
   if (y > 0 && scrollViewPos == y){
      //do something
   }

   scrollViewPos = y;
}
46

   scrollView.getViewTreeObserver()
       .addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                if (scrollView.getChildAt(0).getBottom()
                     <= (scrollView.getHeight() + scrollView.getScrollY())) {
                    //scroll view is at bottom
                } else {
                    //scroll view is not at bottom
                }
            }
        });
Doesn't need to custom ScrollView. Scrollview can host only one direct child, so scrollView.getChildAt(0) is okay. This solution is right even the height of direct child of scroll view is match_parent or wrap_content.
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
15

но я обнаружил, что какое-то устройство (например, Samsung Galaxy Note V) не может достичь 0, после расчета осталось 2 очка. Я предлагаю добавить немного буфера, как показано ниже:

@Override
public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) {
    // We take the last son in the scrollview
    View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1);
    int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));

    // if diff is zero, then the bottom has been reached
    if (diff <= 10) {
        // do stuff
    }
}
Error: User Rate Limit Exceeded Fustigador
3
scrollView = (ScrollView) findViewById(R.id.scrollView);

    scrollView.getViewTreeObserver()
            .addOnScrollChangedListener(new 
            ViewTreeObserver.OnScrollChangedListener() {
                @Override
                public void onScrollChanged() {

                    if (!scrollView.canScrollVertically(1)) {
                        // bottom of scroll view
                    }
                    if (!scrollView.canScrollVertically(-1)) {
                        // top of scroll view


                    }
                }
            });
4

NestedScrollView и этоNestedScrollView.OnScrollChangeListener интерфейс.

https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html

В качестве альтернативы, если ваше приложение ориентировано на API 23 или выше, вы можете использовать следующий метод наScrollView:

View.setOnScrollChangeListener(OnScrollChangeListener listener) 

Затем следуйте примеру, который @Fustigador описал в своем ответе. Однако обратите внимание, что, как описано в @Will, вам следует рассмотреть возможность добавления небольшого буфера на тот случай, если пользователь или система не смогут достичь полного дна списка по любой причине.

Также стоит отметить, что слушатель изменения прокрутки иногда вызывается с отрицательными значениями или значениями, превышающими высоту просмотра. Предположительно эти значения представляют «импульс»; действия прокрутки. Однако, если с ними не обращаться должным образом (пол / абс), они могут вызвать проблемы с определением направления прокрутки, когда вид прокручивается до верхней или нижней части диапазона.

https://developer.android.com/reference/android/view/View.html#setOnScrollChangeListener(android.view.View.OnScrollChangeListener)

101

Помимо исправления, любезно предоставленного Александром, мне пришлось создать интерфейс:

public interface ScrollViewListener {
    void onScrollChanged(ScrollViewExt scrollView, 
                         int x, int y, int oldx, int oldy);
}

Затем мне пришлось переопределить метод OnScrollChanged из ScrollView в моем ScrollViewExt:

public class ScrollViewExt extends ScrollView {
    private ScrollViewListener scrollViewListener = null;
    public ScrollViewExt(Context context) {
        super(context);
    }

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

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

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

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

Теперь, как сказал Александр, поместите имя пакета в тег XML (моя ошибка), заставьте мой класс Activity реализовать интерфейс, созданный ранее, а затем соедините все это вместе:

scroll = (ScrollViewExt) findViewById(R.id.scrollView1);
scroll.setScrollViewListener(this);

А в методе OnScrollChanged, из интерфейса ...

@Override
public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) {
    // We take the last son in the scrollview
    View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1);
    int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));

    // if diff is zero, then the bottom has been reached
    if (diff == 0) {
        // do stuff
    }
}

И это сработало!

Большое спасибо за помощь, Александр!

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededstackoverflow.com/questions/3609297/…
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
3

scrollView.getPaddingBottom() чтобы соответствовать полной высоте просмотра прокрутки, потому что некоторое представление прокрутки времени имеет отступ в файле XML, так что в этом случае он не будет работать.

scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            if (scrollView != null) {
               View view = scrollView.getChildAt(scrollView.getChildCount()-1);
               int diff = (view.getBottom()+scrollView.getPaddingBottom()-(scrollView.getHeight()+scrollView.getScrollY()));

          // if diff is zero, then the bottom has been reached
               if (diff == 0) {
               // do stuff
                }
            }
        }
    });
2

beside a fact, that when u scroll to the bottom, listener is triggered several times, который в моем случаеundesirable, Чтобы избежать такого поведения, я добавил флагscrollPositionChanged  проверяет, изменилась ли даже позиция прокрутки перед повторным вызовом метода.

public class EndDetectingScrollView extends ScrollView {
    private boolean scrollPositionChanged = true;

    private ScrollEndingListener scrollEndingListener;

    public interface ScrollEndingListener {
        void onScrolledToEnd();
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);

        View view = this.getChildAt(this.getChildCount() - 1);
        int diff = (view.getBottom() - (this.getHeight() + this.getScrollY()));
        if (diff <= 0) {
            if (scrollPositionChanged) {
                scrollPositionChanged = false;
                if (scrollEndingListener != null) {
                    scrollEndingListener.onScrolledToEnd();
                }
            }
        } else {
            scrollPositionChanged = true;
        }
    }

    public void setScrollEndingListener(ScrollEndingListener scrollEndingListener) {
        this.scrollEndingListener = scrollEndingListener;
    }
}

Тогда просто установите слушателя

scrollView.setScrollEndingListener(new EndDetectingScrollView.ScrollEndingListener() {
    @Override
    public void onScrolledToEnd() {
        //do your stuff here    
    }
});

Вы можете сделать то же самое, если вы делаете как

scrollView.getViewTreeObserver().addOnScrollChangedListener(...)

но вы должны предоставить флаг из класса, добавив этот слушатель.

Error: User Rate Limit Exceeded

Похожие вопросы