如何区分Android ScrollView的最终用户滚动与编程滚动?

idi*_*dij 6 android scrollview

背景:我有一个ScrollView/TextView对,它接收来自外部源的间歇性文本流.它会在每次更新时自动滚动到底部.

我希望用户能够通过手动滚动到某个地方来突破自动向下滚动模式,但是我不清楚如何将手动滚动与我自己编写的程序滚动区分开来.

我的UI更新在计时器上运行以缓冲重绘:

private Handler outputUpdater = new Handler ();
private static String outputBuffer = "";
private static boolean outputHasChanged = false;
private static final Object lock = new Object ();

private Runnable outputUpdaterTask = new Runnable () {
    public void run () {
        synchronized (lock) {

            // if the output has changed, update the TextView
            if (outputHasChanged) {
                TextView tv = (TextView) findViewById (R.id.textView);
                tv.setText (outputBuffer);
            }

            // if the output has changed, or the scroll hasn't reached the bottom yet
            // then keep scrolling down
            if (outputHasChanged || !scrollAtBottom ()) {
                ScrollView sv = (ScrollView) findViewById (R.id.scrollView);
                sv.fullScroll (View.FOCUS_DOWN);
            }

            outputHasChanged = false;
        }

        outputUpdater.postDelayed (this, 100);
    }
};
Run Code Online (Sandbox Code Playgroud)

scrollAtBottomonScrollChanged处理程序中获取它的价值.

一切正常.fullScroll即使没有文本更新也需要调用,因为fullScroll如果正在进行TextView更新,或者虚拟键盘可见性发生变化等,单个调用并不总是在底部调用.

我希望如果用户手动滚动,我可以知道决定停止呼叫fullScroll.

不幸的是,仅仅将"从底部,自动模式"到"不在底部"的转换视为切换到手动模式的提示似乎还不够,因为各种UI更改似乎也将滚动视图从底部移开(例如虚拟键盘显示).

问题重述: 如何区分用户启动的滚动和编程滚动?

jnt*_*jns 11

您是否尝试过使用booleanwith onTouchEvent,类似于:

boolean userIntercept = false;
@Override
public boolean onTouchEvent(MotionEvent me) {
    int action = me.getAction();
    if (action == MotionEvent.ACTION_MOVE) {
            userIntercept = true;
    }
    return super.onTouchEvent(me);
}
Run Code Online (Sandbox Code Playgroud)

然后在你的outputUpdaterTask:

// if the output has changed, or the scroll hasn't reached the bottom yet
// then keep scrolling down
if (outputHasChanged || !scrollAtBottom () && !userIntercept) {
    ScrollView sv = (ScrollView) findViewById (R.id.scrollView);
    sv.fullScroll (View.FOCUS_DOWN);
}
Run Code Online (Sandbox Code Playgroud)

您只需要确定一种可以返回userIntercept到的方式false,最适合您的应用程序.

  • 谢谢,这是有效的基本想法.为了完整起见,我现在正在做的是:ACTION_MOVE或ACTION_DOWN启动手动模式并打开"手指向下"状态.ACTION_UP关闭"手指向下"状态.如果finger state和atBottom都为true,onScrollChanged和ACTION_UP都会再次打开自动滚动. (4认同)
  • 需要根据手指状态在onScrollChanged中突破手动模式,因为你可以“轻弹”屏幕进行滚动,并且在滚动完成之前你会得到ACTION_UP。 (2认同)