25

我在滚动视图内的文本视图中有固定内容。当用户滚动到某个位置时,我想启动一个活动或触发一个Toast.

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent" android:layout_height="fill_parent"
 android:id="@+id/scroller">
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical" android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TextView android:layout_width="fill_parent" android:id="@+id/story"
   android:layout_height="wrap_content" android:text="@string/lorem"
   android:gravity="fill" />
 </LinearLayout>
</ScrollView>

我的问题是在实现受保护的方法onScrollChanged来找出滚动视图的位置。

我找到了这个答案,有没有更简单的解决方案,而不是声明一个界面,覆盖滚动视图等,如我发布的链接所示?

4

11 回答 11

51

有一种比子类化更简单的方法ScrollView。的ViewTreeObserver对象ScrollView可以用来监听滚动。

由于ViewTreeObserver对象在 的生命周期内可能会发生变化,因此ScrollView我们需要在 上注册一个OnTouchListener以在滚动时ScrollView获取它ViewTreeObserver

final ViewTreeObserver.OnScrollChangedListener onScrollChangedListener = new
                           ViewTreeObserver.OnScrollChangedListener() {

    @Override
    public void onScrollChanged() {
        //do stuff here 
    }
};

final ScrollView scrollView = (ScrollView) findViewById(R.id.scroller);
scrollView.setOnTouchListener(new View.OnTouchListener() {
    private ViewTreeObserver observer;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (observer == null) {
            observer = scrollView.getViewTreeObserver();
            observer.addOnScrollChangedListener(onScrollChangedListener);
        }
        else if (!observer.isAlive()) {
            observer.removeOnScrollChangedListener(onScrollChangedListener);
            observer = scrollView.getViewTreeObserver();
            observer.addOnScrollChangedListener(onScrollChangedListener);
        }

        return false;
    }
});
于 2013-07-04T00:20:41.840 回答
15

不。

ScrollView 不提供滚动事件的侦听器,甚至不提供检查用户向下滚动多远的方法,因此您必须按照链接的建议进行操作。

于 2010-11-24T03:46:38.987 回答
10

这个问题已经相当老了,但万一有人路过(像我一样):

API 23开始,AndroidView有一个OnScrollChangeListener匹配的 setter

Support 库中的NestedScrollView还支持在该 API 级别之前设置滚动侦听器。据我所知,NestedScrollView可以作为正常的替代品使用,ScrollView没有任何问题。

于 2016-04-18T15:16:35.853 回答
8

实际上有一种方法可以知道用户滚动了多远。ScrollView 中的 getScrollY() 方法告诉您这一点。

于 2012-04-16T10:58:34.260 回答
2

我扩展了我的滚动视图。此链接可能会有所帮助。

class MyScroll extends ScrollView {
    boolean onTop=true;
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        //Log.d(TAG, "scroll changed: " + this.getTop() + " "+t);
        if(t <= 0){
            onTop = true;
            //Log.d(TAG, "scroll top: " + t);
            super.onScrollChanged(l, t, oldl, oldt);
            return;
            // reaches the top end
        }
        onTop = false;

        View view = (View) getChildAt(getChildCount()-1);
        int diff = (view.getBottom()-(getHeight()+getScrollY()+view.getTop()));// Calculate the scrolldiff
        if( diff <= 0 ){
            // if diff is zero, then the bottom has been reached
        }
        super.onScrollChanged(l, t, oldl, oldt);
    }
}
于 2016-04-18T15:39:33.473 回答
2

您可以使用此触发器来显示 Toast 或 Start Activity

 scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
             // do something when Scroll  
        }
    });
于 2018-03-26T13:21:07.530 回答
2

您可以使用此代码来检测是向上还是向下滚动

scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            int lastScroll=0;
            @Override
            public void onScrollChanged() {
                int scrollY = scrollView.getScrollY(); // For ScrollView herzontial use getScrollX()

                if (scrollY > lastScroll ) {
                    Log.e("scroll","down scroll"+scrollY);
                } else if (scrollY < lastScroll ) {
                    Log.e("scroll","up scroll"+scrollY);
                }
                lastScroll=scrollY;
            }
        });
于 2019-09-06T18:29:16.770 回答
1

NestedScrollView 就像 android.widget.ScrollView 一样,但它支持在新旧版本的 Android 上同时充当嵌套滚动父项和子项。

1st - 使用 NestedScrollView 绑定而不是 ScrollView

2nd - 设置滚动侦听器,像这样,通过示例检测 headerView 的 Y 轴移动

    nestedScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {

        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            Log.d(TAG, "onScrollChangeForY - scrollY: " + scrollY + " oldScrollY: " + oldScrollY);

            int MOVE = -1, SCROLL_UP = 0, SCROLL_DOWN = 1;
            float initialPositionY = headerView.getY();

            MOVE = scrollY > oldScrollY ? SCROLL_UP : SCROLL_DOWN;

            if (MOVE == SCROLL_UP) {

                int incrementY = scrollY - oldScrollY;

                headerView.setY(initialPositionY - incrementY);

            } else {

                int incrementY = oldScrollY - scrollY;

                headerView.setY(initialPositionY + incrementY);
            }
        }
    });
于 2017-12-12T13:01:34.440 回答
0

只需使用NestedScrollNestedScroll.setOnScrollChangeListener()

于 2017-05-17T21:10:55.393 回答
0

有一个随时可用的组件,它有助于监听 Android 中任意视图的滚动事件。在内部,此组件在具有旧 Android API 的设备上添加 ViewTreeObserver 滚动事件侦听器(类似于在 Shubhadeep Chaudhuri 的回答中提出的建议),并在具有新 Android API(API 级别 23+)的设备上添加 View 滚动事件侦听器。

于 2017-06-13T02:50:52.667 回答
-1

从 API 23 Android M 开始,您可以使用 OnScrollChangeListener。

 scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
        @Override
        public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            //work with parameters
        }
    });
于 2017-11-28T06:48:25.813 回答