检测ScrollView的结束

Fus*_*dor 66 android android-scrollview

我有一个应用程序,它有一个使用的活动ScrollView.我需要检测用户何时到达底部ScrollView.我做了一些googleing,我发现这个页面在哪里解释.但是,在这个例子中,那些人扩展了ScrollView.正如我所说,我需要扩展Activity.

所以,我说"好吧,让我们尝试使自定义类扩展ScrollView,覆盖onScrollChanged()方法,检测滚动结束,并相应地采取行动".

我做了,但在这一行:

scroll = (ScrollViewExt) findViewById(R.id.scrollView1);
Run Code Online (Sandbox Code Playgroud)

它扔了一个 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>
Run Code Online (Sandbox Code Playgroud)

我改变了它从TextViewWebView到能证明里面的文字.我想要实现的是"在完全阅读合同条款之前,接受按钮不会激活"的事情.我的扩展类称为ScrollViewExt.如果我更改标签ScrollView,ScrollViewExt它会抛出一个

android.view.InflateException: Binary XML file line #44: Error inflating class ScrollViewExt
Run Code Online (Sandbox Code Playgroud)

因为它不懂标签ScrollViewEx.我不认为它有解决方案......

谢谢你的回答!

Fus*_*dor 105

做到了!

除了Alexandre友好地提供给我的修复,我必须创建一个接口:

public interface ScrollViewListener {
    void onScrollChanged(ScrollViewExt scrollView, 
                         int x, int y, int oldx, int oldy);
}
Run Code Online (Sandbox Code Playgroud)

然后,我必须在我的ScrollViewExt中从ScrollView覆盖OnScrollChanged方法:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,正如Alexandre所说,将包名放在XML标签中(我的错),让我的Activity类实现之前创建的接口,然后将它们放在一起:

scroll = (ScrollViewExt) findViewById(R.id.scrollView1);
scroll.setScrollViewListener(this);
Run Code Online (Sandbox Code Playgroud)

而在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
    }
}
Run Code Online (Sandbox Code Playgroud)

它奏效了!

非常感谢你的帮助,Alexandre!


Thi*_*nce 58

我找到了一种简单的方法来检测这个:

   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
                }
            }
        });
Run Code Online (Sandbox Code Playgroud)
  • 不需要自定义ScrollView.
  • Scrollview只能托管一个直接子项,因此scrollView.getChildAt(0)没问题.
  • 这个解决方案是正确的,即使滚动视图的直接子节点的高度是match_parentwrap_content.

  • 为避免多次调用bottom,将"<="替换为"==" (7认同)

yuv*_*val 35

所有这些答案都是如此复杂,但有一个简单的内置方法可以实现这一点: canScrollVertically(int)

例如:

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

这也适用于RecyclerView,ListView,以及实现该方法以来的任何其他视图View.

如果你有一个水平的ScrollView,可以实现相同的 canScrollHorizontally(int)

  • 完美答案!经测试! (7认同)
  • 真的有帮助。谢谢! (3认同)
  • 它必须是一个可接受的答案,它很简单,而且效果很好 (3认同)
  • 为了完整起见,使用 `!scrollView.canScrollHorizo​​ntally(1)` 来检查它是否已经在右端,如果它在左边,则使用 `!scrollView.canScrollHorizo​​ntally(-1)`。 (3认同)

小智 16

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
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 13

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


                    }
                }
            });
Run Code Online (Sandbox Code Playgroud)


小智 10

编辑

通过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>
Run Code Online (Sandbox Code Playgroud)

编辑结束

你可以发布xml内容吗?

我认为你可以简单地添加一个滚动监听器并检查最后一个项目是否是listview中最新的项目,如:

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
        }
    }
});
Run Code Online (Sandbox Code Playgroud)


小智 7

我浏览了互联网上的解决方案。大多数解决方案在我正在从事的项目中不起作用。以下解决方案对我来说效果很好。

使用 onScrollChangeListener (适用于 API 23):

   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
            @Override
            public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {

                int bottom =   (scrollView.getChildAt(scrollView.getChildCount() - 1)).getHeight()-scrollView.getHeight()-scrollY;

                if(scrollY==0){
                    //top detected
                }
                if(bottom==0){
                    //bottom detected
                }
            }
        });
    }
Run Code Online (Sandbox Code Playgroud)

在 TreeObserver 上使用scrollChangeListener

 scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            int bottom =   (scrollView.getChildAt(scrollView.getChildCount() - 1)).getHeight()-scrollView.getHeight()-scrollView.getScrollY();

            if(scrollView.getScrollY()==0){
                //top detected
            }
            if(bottom==0) {
                //bottom detected
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

希望这个解决方案有帮助:)


The*_*eIT 5

您可以使用支持库NestedScrollView及其NestedScrollView.OnScrollChangeListener界面。

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

或者,如果您的应用面向 API 23 或更高版本,您可以在 上使用以下方法ScrollView

View.setOnScrollChangeListener(OnScrollChangeListener listener) 
Run Code Online (Sandbox Code Playgroud)

然后按照@Fustigador 在他的回答中描述的示例进行操作。但是请注意,正如@Will 所述,您应该考虑添加一个小缓冲区,以防用户或系统因任何原因无法到达列表的完整底部。

另外值得注意的是,滚动更改侦听器有时会以负值或大于视图高度的值被调用。大概这些值代表滚动动作的“动量”。但是,除非处理得当(地板/绝对),否则当视图滚动到范围的顶部或底部时,它们可能会导致检测滚动方向的问题。

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