【问题标题】:stop scrollView in the middle of the scroll在滚动中间停止滚动视图
【发布时间】:2013-06-26 04:49:37
【问题描述】:

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

我已尝试禁用滚动视图,如 here 所述,但它仅在滚动视图完全停止且无法在投掷过程中停止时禁用。

当达到某个视图位置或某个 y 值时,有什么方法可以停止滚动视图?

【问题讨论】:

  • 你试过lazy loading
  • 这样的应用行为很可能会破坏用户体验,你确定要实现吗?

标签: android scrollview onfling onscroll


【解决方案1】:

我遇到了同样的问题。

listView.smoothScrollBy(0,0)

这将停止滚动。

【讨论】:

  • 效果很好。我对此的补充 - 如果尝试使用 scrollTo(0, 0) 例如重置滚动视图的位置,如果滚动视图处于惯性(甩动)阶段,它就不起作用(scrollTo)。所以解决方法是调用smoothScrollTo(0, 0);
  • scrollBy(0,0) 也可以根据情况工作。
  • 完美——这也消除了用户产生的惯性!
【解决方案2】:

要在特定点停止投掷,只需调用

fling(0)

如果您只关心投掷,我认为这是最合乎逻辑的方式,因为 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.
 */

【讨论】:

  • 在这种情况下,getScrollX() 的值将是您想要的其他值。会有副作用。
【解决方案3】:

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

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

在我的例子中,我希望我的列表在用户按下按钮时跳转到 top(位置=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 来停止滚动。

【讨论】:

  • 虽然它没有直接回答这个问题,但这正是我正在寻找的解决方案。谢谢!
  • 这真的会停止任何现有的滚动吗?例如。如果我抛出scrollview,然后调用smoothScrollTo,抛出似乎在onScrollChanged回调中继续。
  • 我从一个按钮触发了这个(跳转到列表中的特定点),它确实为我停止了滚动。例如,如果我轻弹列表,在它滚动时按下按钮,它会跳转,然后平滑滚动到我想要的位置,并且滚动将停止(轻弹不再处于活动状态)。我根本没有使用过 onScrollChanged。我只是在使用标准的 ListAdapter,而不是自己处理影片。
【解决方案4】:

您需要禁用ScrollView 处理投掷操作。为此,只需覆盖ScrollView 中的fling 方法并注释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);
     */
    }
 }

【讨论】:

  • 但它不会永久禁用投掷吗?我希望在滚动视图滚动到特定 y 值时停止投掷。
【解决方案5】:

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

我已经设法通过覆盖onScrollChanged 然后调用smoothScrollTo 将ScrollView 停止在特定的y 坐标。我允许用户通过保持一个布尔值来继续向下滚动超过该点,该布尔值指示这是否是第一次投掷/拖动。从下到上滚动也是如此——我再次在同一点停止滚动。然后让用户再次继续向上滚动。

代码如下所示:

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;
            }
        }
    });
}

【讨论】:

    【解决方案6】:

    其实我是用这个方法的:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多