Android 我可以为 ScrollView 设置 onScrollListener 吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10713312/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:42:53  来源:igfitidea点击:

Can I have onScrollListener for a ScrollView?

androidlistenerscrollview

提问by arnp

I am using a HorizontalScrollViewin a layout and I need to identify the user have reached the start and end point of the scroll.

HorizontalScrollView在布局中使用 a ,我需要确定用户已到达滚动的起点和终点。

For ListViewI have tried a the onScrollListenerand it is possible to find the start and end point of scroll.

因为ListView我已经尝试过,onScrollListener并且可以找到滚动的起点和终点。

I tried to do the same in my Scrollviewbut it seems not possible. Is there any other possible ways to achieve what I need.

我试图在我的身上做同样的事情,Scrollview但似乎不可能。有没有其他可能的方法来实现我所需要的。

回答by Zbun

Every instance of View calls getViewTreeObserver(). Now when holding an instance of ViewTreeObserver, you can add an OnScrollChangedListener()to it using the method addOnScrollChangedListener().

View 的每个实例都调用getViewTreeObserver(). 现在,当持有 的实例时ViewTreeObserver,您可以OnScrollChangedListener()使用 方法向其添加addOnScrollChangedListener()

You can see more information about this class here.

您可以在此处查看有关此类的更多信息。

It lets you be aware of every scrolling event - but without the coordinates. You can get them by using getScrollY()or getScrollX()from within the listener though.

它让您知道每个滚动事件 - 但没有坐标。不过,您可以通过使用getScrollY()getScrollX()从侦听器中获取它们。

scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
        int scrollY = rootScrollView.getScrollY(); // For ScrollView
        int scrollX = rootScrollView.getScrollX(); // For HorizontalScrollView
        // DO SOMETHING WITH THE SCROLL COORDINATES
    }
});

回答by Midhun Vijayakumar

This might be very useful. Use NestedScrollViewinstead of ScrollView. Support Library 23.1 introduced an OnScrollChangeListenerto NestedScrollView. So you can do something like this.

这可能非常有用。使用NestedScrollView代替ScrollView。支持库23.1引入了一个OnScrollChangeListenerNestedScrollView。所以你可以做这样的事情。

 myScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            Log.d("ScrollView","scrollX_"+scrollX+"_scrollY_"+scrollY+"_oldScrollX_"+oldScrollX+"_oldScrollY_"+oldScrollY);
            //Do something
        }
    });

回答by ZaBlanc

Here's a derived HorizontalScrollView I wrote to handle notifications about scrolling and scroll ending. It properly handles when a user has stopped actively scrolling andwhen it fully decelerates after a user lets go:

这是我编写的派生 Horizo​​ntalScrollView 来处理有关滚动和滚动结束的通知。当用户停止主动滚动以及在用户放手后完全减速时,它会正确处理:

public class ObservableHorizontalScrollView extends HorizontalScrollView {
    public interface OnScrollListener {
        public void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY);
        public void onEndScroll(ObservableHorizontalScrollView scrollView);
    }

    private boolean mIsScrolling;
    private boolean mIsTouching;
    private Runnable mScrollingRunnable;
    private OnScrollListener mOnScrollListener;

    public ObservableHorizontalScrollView(Context context) {
        this(context, null, 0);
    }

    public ObservableHorizontalScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();

        if (action == MotionEvent.ACTION_MOVE) {
            mIsTouching = true;
            mIsScrolling = true;
        } else if (action == MotionEvent.ACTION_UP) {
            if (mIsTouching && !mIsScrolling) {
                if (mOnScrollListener != null) {
                    mOnScrollListener.onEndScroll(this);
                }
            }

            mIsTouching = false;
        }

        return super.onTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldX, int oldY) {
        super.onScrollChanged(x, y, oldX, oldY);

        if (Math.abs(oldX - x) > 0) {
            if (mScrollingRunnable != null) {
                removeCallbacks(mScrollingRunnable);
            }

            mScrollingRunnable = new Runnable() {
                public void run() {
                    if (mIsScrolling && !mIsTouching) {
                        if (mOnScrollListener != null) {
                            mOnScrollListener.onEndScroll(ObservableHorizontalScrollView.this);
                        }
                    }

                    mIsScrolling = false;
                    mScrollingRunnable = null;
                }
            };

            postDelayed(mScrollingRunnable, 200);
        }

        if (mOnScrollListener != null) {
            mOnScrollListener.onScrollChanged(this, x, y, oldX, oldY);
        }
    }

    public OnScrollListener getOnScrollListener() {
        return mOnScrollListener;
    }

    public void setOnScrollListener(OnScrollListener mOnEndScrollListener) {
        this.mOnScrollListener = mOnEndScrollListener;
    }

}

回答by mcspayne

If you want to know the scroll position of a view, then you can use the following extension function on View class:

如果你想知道一个视图的滚动位置,那么你可以在 View 类上使用以下扩展函数:

fun View?.onScroll(callback: (x: Int, y: Int) -> Unit) {
    var oldX = 0
    var oldY = 0
    this?.viewTreeObserver?.addOnScrollChangedListener {
        if (oldX != scrollX || oldY != scrollY) {
            callback(scrollX, scrollY)
            oldX = scrollX
            oldY = scrollY
        }
    }
}

回答by Cristan

You can use NestedScrollViewinstead of ScrollView. However, when using a Kotlin Lambda, it won't know you want NestedScrollView's setOnScrollChangeListenerinstead of the one at View (which is API level 23). You can fix this by specifying the first parameter as a NestedScrollView.

您可以使用NestedScrollView代替ScrollView. 但是,当使用 Kotlin Lambda 时,它不会知道您想要 NestedScrollViewsetOnScrollChangeListener而不是 View(这是 API 级别 23)。您可以通过将第一个参数指定为 NestedScrollView 来解决此问题。

nestedScrollView.setOnScrollChangeListener { _: NestedScrollView, scrollX: Int, scrollY: Int, _: Int, _: Int ->
    Log.d("ScrollView", "Scrolled to $scrollX, $scrollY")
}

回答by Chuanxing Zhao

you can define a custom ScrollView class, & add an interface be called when scrolling like this:

您可以定义一个自定义的 ScrollView 类,并添加一个在滚动时调用的界面,如下所示:

public class ScrollChangeListenerScrollView extends HorizontalScrollView {


private MyScrollListener mMyScrollListener;

public ScrollChangeListenerScrollView(Context context) {
    super(context);
}

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

public ScrollChangeListenerScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}


public void setOnMyScrollListener(MyScrollListener myScrollListener){
    this.mMyScrollListener = myScrollListener;
}


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

}

public interface MyScrollListener {
    void onScrollChange(View view,int scrollX,int scrollY,int oldScrollX, int oldScrollY);
}

}

回答by Wirote W.

    // --------Start Scroll Bar Slide--------
    final HorizontalScrollView xHorizontalScrollViewHeader = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewHeader);
    final HorizontalScrollView xHorizontalScrollViewData = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewData);
    xHorizontalScrollViewData.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            int scrollX; int scrollY;
            scrollX=xHorizontalScrollViewData.getScrollX();
            scrollY=xHorizontalScrollViewData.getScrollY();
            xHorizontalScrollViewHeader.scrollTo(scrollX, scrollY);
        }
    });
    // ---------End Scroll Bar Slide---------