滚动型检测结束滚动型检测结束(Detect end of ScrollView)

2019-05-13 15:31发布

我有一个应用程序,有一个使用的活动ScrollView 。 我需要在用户获取到的底部,以检测ScrollView 。 我做了一些googleing,我发现这个网页 ,其中解释。 但是,在本例中,该人延伸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>

我改变了它TextViewWebView能够证明里面的文字。 我想实现的是“接受按钮不激活直到合同的条款仔细阅读”的事情。 我的扩展类被称为ScrollViewEx吨。 如果我改变标签ScrollViewScrollViewExt它抛出一个

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

因为它不理解的标签ScrollViewEx 。 我不认为它有一个解决方案...

谢谢您的回答!

Answer 1:

做到了!

除了修复亚历山大好心给我的,我不得不创建一个接口:

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

于是,我不得不重写从滚动型的OnScrollChanged方法在我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
    }
}

和它的工作!

非常感谢您的帮助,亚历山大!



Answer 2:

我发现了一个简单的方法来检测这样的:

   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
                }
            }
        });
  • 不需要自定义滚动型。
  • 滚动型只能承载一个直接的孩子,所以scrollView.getChildAt(0)是好的。
  • 该解决方案是滚动视图的直接孩子的权利,即使高度match_parentWRAP_CONTENT。


Answer 3:

所有这些问题的答案是如此复杂,但有内置的方法简单,完成此: 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

如果你有一个水平滚动型,同样可以实现canScrollHorizontally(int)



Answer 4:

Fustigador答案是伟大的,但我发现了一些设备(如三星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
    }
}


Answer 5:

编辑

随着你的XML的内容,我可以看到你使用滚动型。 如果你想使用自定义视图,你必须写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>

编辑结束

你可以发布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
        }
    }
});


Answer 6:

您可以使用支持图书馆的NestedScrollView和它的NestedScrollView.OnScrollChangeListener接口。

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

另外,如果您的应用程序的目标是API 23或以上,你可以使用在以下方法的ScrollView

View.setOnScrollChangeListener(OnScrollChangeListener listener) 

然后按照@Fustigador在他的回答中描述的例子。 但是请注意,如@Will描述,你应该考虑增加一个小的缓冲区,以防用户或系统不能达到列表的底部完全出于任何原因。

还值得注意的是,滚动改变收听者将有时与负值被调用或值比视图高度。 据推测,这些值表示的滚动操作的“势头”。 然而,除非适当的处理(地板/ ABS),他们可能会导致问题检测滚动方向,当视图被滚动到该范围的顶部或底部。

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



Answer 7:

我们应该时时补充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
                }
            }
        }
    });


Answer 8:

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


                    }
                }
            });


Answer 9:

大多数的答案工作的事实旁边,即当u滚动至底部,听者多次触发 ,这在我的情况是不可取的 。 为了避免这种行为,我已经添加标志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    
    }
});

你可以做同样的事情如果u做到像

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

但你必须从你的类添加此聆听者提供标志。



Answer 10:

要确定您是否在您的自定义结束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;
}


文章来源: Detect end of ScrollView