问题 在滚动的中间停止scrollView


我有一个包含大量内容的滚动视图。现在当用户进行投掷或向下滚动时,我希望滚动视图停在特定的视图位置,我正在做一些动画,然后用户可以再次投掷或向下滚动。

我已经尝试过如上所述禁用scrollview 这里 但它只在滚动视图完全停止并且无法在投掷过程中停止时禁用。

有什么办法可以在达到某个视图位置或某个y值时停止滚动视图的投掷?


4157
2018-06-26 04:49


起源

你有没有尝试过 懒加载 - CRUSADER
这样的应用程序行为可能会破坏用户体验,您确定要实现它吗? - Egor


答案:


我的解决方案遇到了同样的问题。

listView.smoothScrollBy(0,0)

这将停止滚动。


8
2017-07-07 06:23



效果很好。我对此的补充 - 如果有人试图使用scrollTo(0,0)来重置scrollview的位置,那么如果scrollview处于惯性(fling)阶段则它不起作用(scrollTo)。所以解决方法是调用smoothScrollTo(0,0); - luky
scrollBy(0,0)也可以根据情况工作。 - Adil Aliyev


要在特定点停止投掷,只需致电

fling(0)

如果你只关心flings,这是我的opionon最合乎逻辑的方式,因为 velosityY设置为0,从而立即停止投掷。

这是fling方法的javadoc:

/**
 * Fling the scroll view
 *
 * @param velocityY The initial velocity in the Y direction. Positive
 *                  numbers mean that the finger/cursor is moving down the screen,
 *                  which means we want to scroll towards the top.
 */

3
2017-12-21 19:34



在这种情况下,getScrollX()的值将是你想要的其他东西。它会产生副作用。 - Adil Aliyev


一种方法可能是使用 smoothScrollToPosition,停止任何现有的滚动动作。请注意,此方法需要API级别> = 8(Android 2.2,Froyo)。

请注意,如果当前位置远离所需位置,那么平滑滚动将花费相当长的时间并且看起来有点不稳定(至少在我对Android 4.4 KitKat的测试中)。我还发现调用setSelection和smoothScrollToPosition的组合有时会导致位置略微“错过”,这似乎只有在当前位置非常接近所需位置时才会发生。

在我的情况下,我希望我的列表跳转到 最佳 (position = 0)当用户按下按钮时(这与您的使用情况略有不同,因此您需要根据需要进行调整)。

我使用以下方法

private void smartScrollToPosition(ListView listView, int desiredPosition) {
    // If we are far away from the desired position, jump closer and then smooth scroll
    // Note: we implement this ourselves because smoothScrollToPositionFromTop
    // requires API 11, and it is slow and janky if the scroll distance is large,
    // and smoothScrollToPosition takes too long if the scroll distance is large.
    // Jumping close and scrolling the remaining distance gives a good compromise.
    int currentPosition = listView.getFirstVisiblePosition();
    int maxScrollDistance = 10;
    if (currentPosition - desiredPosition >= maxScrollDistance) {
        listView.setSelection(desiredPosition + maxScrollDistance);
    } else if (desiredPosition - currentPosition >= maxScrollDistance) {
        listView.setSelection(desiredPosition - maxScrollDistance);
    }
    listView.smoothScrollToPosition(desiredPosition); // requires API 8
}

在我的按钮动作处理程序中,我按如下方式调用它

    case R.id.action_go_to_today:
        ListView listView = (ListView) findViewById(R.id.lessonsListView);
        smartScrollToPosition(listView, 0); // scroll to top
        return true;

以上并没有直接回答你的问题,但如果你能检测到当前位置何时处于或接近你想要的位置,那么也许你可以使用 smoothScrollToPosition 停止滚动。


2
2018-03-15 15:13



虽然它没有直接回答这个问题,但这正是我一直在寻找的解决方案。谢谢! - akent
这真的会阻止任何现有的滚动吗?例如。如果我扔滚动视图,然后调用smoothScrollTo,fling似乎在onScrollChanged回调中继续。 - Alf
我从一个按钮触发(跳转到列表中的特定点),它确实停止了我的滚动。例如,如果我轻弹列表,当它滚动时我按下按钮,它会跳转然后平滑滚动到我想要的位置,滚动将停止(轻弹不再有效)。我根本没用过onScrollChanged。我只是使用标准的ListAdapter,而不是自己处理电影。 - avparker


你需要禁用 ScrollView 处理投掷操作。要做到这一点,只需覆盖 fling 方法 ScrollView 和评论 super.fling()。让我知道这个是否奏效 !

public class CustomScrollView extends ScrollView {

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
    {
    return false;
    }

    @Override
    public void fling (int velocityY)
    {
    /*Scroll view is no longer gonna handle scroll velocity.
    * super.fling(velocityY);
     */
    }
 }

1
2018-06-26 05:48



但它不会永久禁用这种投掷吗?当滚动视图滚动到特定的y值时,我希望停止投掷。 - Deepak Senapati


我正在努力实现类似的情况。我有一个部分解决方案:

我设法通过覆盖在特定的y坐标处停止ScrollView onScrollChanged 然后打电话 smoothScrollTo。我允许用户通过保持一个布尔值继续向下滚动到该点,该布尔值指示这是否是第一个fling / drag。滚动从下到上也是如此 - 我再次停止滚动到同一点。然后允许用户继续向上滚动。

代码看起来像这样:

boolean beenThereFromTop = false;
boolean beenThereFromBottom = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);

    scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {

        @Override
        public void onScrollChanged() {

            TextView whereToStop = (TextView) findViewById(R.id.whereToStop);
            final int y = whereToStop.getBottom();

            int scrollY = scrollView.getScrollY();

// manage scrolling from top to bottom

            if (scrollY > y) {
                if (!beenThereFromTop) {
                    beenThereFromTop = true;
                    scrollView.post(new Runnable() {
                        @Override
                        public void run() {
                            scrollView.smoothScrollTo(0, y);
                        }
                    });
                }
            }
            if (scrollY < y && beenThereFromTop) {
                beenThereFromTop = false;
            }

// manage scrolling from bottom to top

            if (scrollY < y) {
                if (!beenThereFromBottom) {
                    beenThereFromBottom = true;
                    scrollView.post(new Runnable() {
                        @Override
                        public void run() {
                            scrollView.smoothScrollTo(0, y);
                        }
                    });
                }
            }
            if (scrollY > y && beenThereFromBottom) {
                beenThereFromBottom = false;
            }
        }
    });
}

1
2018-02-03 15:43





那么我实际上使用这种方法:

 list.post(new Runnable() 
                        {
                            @Override
                            public void run() 
                            {
                               list.smoothScrollToPositionFromTop(arg2, 150); 
                            }
                        });

0
2018-04-23 13:50