Android 滚动视图 onScrollChanged
Posted
技术标签:
【中文标题】Android 滚动视图 onScrollChanged【英文标题】:Android scrollview onScrollChanged 【发布时间】:2011-05-14 20:46:18 【问题描述】:我在滚动视图内的文本视图中有固定内容。当用户滚动到某个位置时,我想启动一个活动或触发一个Toast
。
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_ android:layout_
android:id="@+id/scroller">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_
android:layout_>
<TextView android:layout_ android:id="@+id/story"
android:layout_ android:text="@string/lorem"
android:gravity="fill" />
</LinearLayout>
</ScrollView>
我的问题是在实现受保护的方法onScrollChanged
以找出滚动视图的位置。
我找到了this 的答案,有没有更简单的解决方案,而不是声明一个界面,覆盖我发布的链接上的滚动视图等?
【问题讨论】:
你可以使用这个***.com/questions/10316743/detect-end-of-scrollview 【参考方案1】:有一种比继承ScrollView
更简单的方法。 ScrollView
的 ViewTreeObserver
对象可用于监听滚动。
由于ViewTreeObserver
对象在ScrollView
的生命周期内可能会发生变化,因此我们需要在ScrollView
上注册一个OnTouchListener
,以便在滚动时获得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;
);
【讨论】:
这并不一定比继承ScrollView
容易。它实际上是更多的代码。如果你是子类,你可以重写 onScrollChanged
方法。
我试过这个,对于相同的滚动 Y 值,它似乎触发了 20 次或更多次事件。看起来不太理想。
嗯……这段代码有一个大问题!这个问题导致了@RandomEngy评论中的错误。因此,我不知道为什么它的投票率如此之高。它在 SCROLL 上的每个触摸事件上添加此侦听器。因此,基本上,如果您单击滚动 20 次,它将导致对侦听器的 20 次调用。侦听器应该只添加一次。例如像这样:scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() @Override public void onScrollChanged() //do stuff );
。不在触摸方法内
或者更糟的是,它可能会在示例中添加至少 40 个侦听器(每次点击至少 TOUCH_DOWN 和 TOUCH_UP)。
我有OnTouchListener
,因为documentation 说“返回的 ViewTreeObserver 观察者不能保证在此视图的生命周期内保持有效”。我已经编辑了答案,因此如果 ViewTreeObserver
不再存在,对其的回调将被删除并添加到 View
的当前 ViewtreeObserver
。【参考方案2】:
没有。
ScrollView 不提供滚动事件的侦听器,甚至不提供检查用户向下滚动多远的方法,因此您必须按照链接的建议进行操作。
【讨论】:
有一个方法 onScrollChanged 可以被覆盖。同样可以使用getScrollX,getScrollY。 现在看来这个答案是无效的。从 API 23 (M) 开始,有一个名为“OnScrollChangeListener”的监听器 scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() @Override public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) //使用参数 ); @S.D.NChanakaFernando 还应该注意的是,在滚动方面,它仍然没有提供针对具体细节的内置解决方案。例如,如果您想检测滚动的结束,则必须使用onScrollChangeListener
手动执行此操作,这非常烦人。以下是遇到此问题的任何人的一些建议:***.com/questions/8181828/…【参考方案3】:
这个问题已经相当老了,但万一有人路过(比如我):
从 API 23 开始,Android 的 View
有一个 OnScrollChangeListener
和 matching setter。
支持库中的NestedScrollView 还支持在该 API 级别之前设置滚动侦听器。据我所知,NestedScrollView
可以用来替代普通的ScrollView
,没有任何问题。
【讨论】:
没有向后兼容性 @define 很好,支持库中有NestedScrollView
,你可以使用它而不是常规的Scrollview
没有问题
对不起,由于某种原因,我错过了你提到它的部分。无论如何,谢谢
@define 我只是没有提到您可以使用 NestedScrollView 而不是普通的。我会把它添加到答案中。
这很棒。我们支持 API 18+,我真的很想要这个库存功能。谢谢!【参考方案4】:
实际上有一种方法可以知道用户滚动了多远。 ScrollView 的 getScrollY() 方法告诉你。
【讨论】:
不,据此:***.com/questions/2132370/… 我在公司的一个项目中使用了这个解决方案。在我在这里发布一些东西之前,我会测试一切。也许你也应该这样做? 抱歉,误读了问题。它适用于ScrollView
,但不适用于ListView
或GridView
。【参考方案5】:
我扩展了我的滚动视图。 This link 可能会有所帮助。
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);
【讨论】:
【参考方案6】:您可以使用此触发器来显示 Toast 或 Start Activity
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener()
@Override
public void onScrollChanged()
// do something when Scroll
);
【讨论】:
【参考方案7】:您可以使用此代码来检测是向上还是向下滚动
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;
);
【讨论】:
【参考方案8】: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);
);
【讨论】:
【参考方案9】:有ready for use component,它有助于监听Android中任意视图的滚动事件。在内部,此组件在具有旧 Android API 的设备上添加 ViewTreeObserver 滚动事件侦听器(类似于 Shubhadeep Chaudhuri 的回答中提出的建议),并在具有新 Android API(API 级别 23+)的设备上添加 View 滚动事件侦听器。
【讨论】:
【参考方案10】:只需使用NestedScroll
和NestedScroll.setOnScrollChangeListener()
。
【讨论】:
【参考方案11】:从 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
);
【讨论】:
以上是关于Android 滚动视图 onScrollChanged的主要内容,如果未能解决你的问题,请参考以下文章