android:smoothScrollToPosition()无法正常工作

use*_*520 51 android listview selection smooth-scrolling android-arrayadapter

在将一个元素添加到与listview关联的arrayadapter之后,我试图平滑地滚动到列表的最后一个元素.问题是它只是滚动到一个随机位置

arrayadapter.add(item);
//DOES NOT WORK CORRECTLY:
listview.smoothScrollToPosition(arrayadapter.getCount()-1);

//WORKS JUST FINE:
listview.setSelection(arrayadapter.getCount()-1);
Run Code Online (Sandbox Code Playgroud)

Mar*_*ini 58

您可能希望告诉ListView在UI线程可以处理它时发布滚动(这就是为什么它不能正确滚动).SmoothScroll需要做很多工作,而不是只是去一个忽略速度/时间/等的位置.("动画"所需).

因此你应该做的事情如下:

    getListView().post(new Runnable() {
        @Override
        public void run() {
            getListView().smoothScrollToPosition(pos);
        }
    });
Run Code Online (Sandbox Code Playgroud)

  • 为'post`的想法+1.但是,我偶然发现`smoothScrollToPosition`仍然不起作用的情况,在窗口小部件的顶部和要滚动到的位置中的项之间留下一个小的偏移空间.在这些情况下,`setSelection`(当然与`post`结合使用)完美无瑕. (13认同)
  • 这个人的名字是@RomainGuy BTW. (5认同)

Lar*_*erg 13

(从我的回答中复制:smoothScrollToPositionFromTop()并不总是像它应该的那样工作)

这是一个已知的错误.请参阅https://code.google.com/p/android/issues/detail?id=36062

但是,我实现了这个解决方案,处理可能发生的所有边缘情况:

第一次调用smothScrollToPositionFromTop(position)然后,当滚动完成时,调用setSelection(position).后一个调用通过直接跳到所需位置来纠正不完整的滚动.这样做,用户仍然会将其动画滚动到此位置.

我在两个辅助方法中实现了这个解决方法:

smoothScrollToPosition()

public static void smoothScrollToPosition(final AbsListView view, final int position) {
    View child = getChildAtPosition(view, position);
    // There's no need to scroll if child is already at top or view is already scrolled to its end
    if ((child != null) && ((child.getTop() == 0) || ((child.getTop() > 0) && !view.canScrollVertically(1)))) {
        return;
    }

    view.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(final AbsListView view, final int scrollState) {
            if (scrollState == SCROLL_STATE_IDLE) {
                view.setOnScrollListener(null);

                // Fix for scrolling bug
                new Handler().post(new Runnable() {
                    @Override
                    public void run() {
                        view.setSelection(position);
                    }
                });
            }
        }

        @Override
        public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
                                 final int totalItemCount) { }
    });

    // Perform scrolling to position
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            view.smoothScrollToPositionFromTop(position, 0);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

getChildAtPosition()

public static View getChildAtPosition(final AdapterView view, final int position) {
    final int index = position - view.getFirstVisiblePosition();
    if ((index >= 0) && (index < view.getChildCount())) {
        return view.getChildAt(index);
    } else {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)


Tao*_*ang 6

您应该使用setSelection()方法.

  • 它不一定相同,您可能不希望选择项目,或者您可以只是寻找平滑效果 (2认同)
  • `setSelection` 确实适用于 `smoothScrollToPosition` 不适用的地方,但如果您能告诉我们为什么会这样,那将会很有帮助。 (2认同)
  • @GiulioPiancastelli smoothScrollToPosition不起作用,因为它应该向所需位置滚动少量.这意味着它不适用于长列表,甚至不适用于远远超过100dp左右的项目.文档不清楚,但它是如何实际工作的.如果您感兴趣,可以通过检查实际的实现代码来了解更多信息. (2认同)

Sid*_*kar 5

使用 LayoutManager 平滑滚动

layoutManager.smoothScrollToPosition(recyclerView, new RecyclerView.State(), position);
Run Code Online (Sandbox Code Playgroud)


Cod*_*oet 1

打完电话之后还arrayadapter.notifyDataSetChanged()打吗arrayadapter.add()?另外可以肯定的是,smoothScrollToPosition是否setSelection有可用的方法,而ListView不是arrayadapter您上面提到的那样。

无论如何,看看这是否有帮助: smoothScrollToPosition after notificationDataSetChanged not work in android