android:smoothScrollToPosition() 无法正常工作

Posted

技术标签:

【中文标题】android:smoothScrollToPosition() 无法正常工作【英文标题】:android: smoothScrollToPosition() not working correctly 【发布时间】:2012-07-11 00:32:31 【问题描述】:

在将元素添加到与列表视图关联的数组适配器后,我正在尝试平滑滚动到列表的最后一个元素。 问题是它只是滚动到一个随机位置

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

//WORKS JUST FINE:
listview.setSelection(arrayadapter.getCount()-1);

【问题讨论】:

这种方法对我没用。 已知错误:见答案***.com/questions/14479078/… 【参考方案1】:

您可能想告诉 ListView 在 UI 线程可以处理它时发布滚动(这就是您的滚动不正确的原因)。 SmoothScroll 需要做很多工作,而不是仅仅去一个忽略速度/时间/等的位置。 (对于“动画”是必需的)。

因此你应该这样做:

    getListView().post(new Runnable() 
        @Override
        public void run() 
            getListView().smoothScrollToPosition(pos);
        
    );

【讨论】:

+1 表示post 的想法。但是,我偶然发现smoothScrollToPosition 仍然不起作用的情况,在小部件顶部和要滚动到的位置的项目之间留下一个小的偏移空间。在这些情况下,setSelection(当然与post 结合使用)可以完美运行。 是的,我也是。 ListViews 远不如 UITableView 等。这很可悲,因为列表是移动设备的核心概念,屏幕尺寸受到影响,所以我们必须滚动内容。无论如何,正如您所知,滚动工作,您只需要了解规则,布局必须已经布局,您必须在 UI 线程中进行,您必须发布它以便列表可以排队操作等。卷轴必须发生很多魔法才能发生。我敢肯定@RomanianGuy 可以对此有所了解。在大多数情况下,iSO 实施仍然完美无缺。 这个人的名字是@RomainGuy BTW。 啊@GiulioPiancastelli 谢谢 :) 一个错字,但现在不能编辑。 这里有一个更完整的解决方法:***.com/questions/14479078/…【参考方案2】:

(复制自我的回答:smoothScrollToPositionFromTop() is not always working like it should)

这是一个已知的错误。见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);
        
    );

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;
    

【讨论】:

【参考方案3】:

你应该使用 setSelection() 方法。

【讨论】:

不一定一样,你可能不希望项目被选中,或者你只是在寻找平滑的效果 它实际上帮助了我,而不是什么都没发生,它仍然被滚动到列表的最后。 setSelection 确实适用于 smoothScrollToPosition 不适用的地方,但如果您能告诉我们为什么会这样,那将会很有帮助。 @GiulioPiancastelli smoothScrollToPosition 不起作用,因为它应该向所需位置滚动少量。这意味着它不适用于长列表,甚至不适用于远超过 100dp 左右的项目。文档并不清楚,但这就是它的实际工作方式。如果您有兴趣,您可能可以通过查看实际的实现代码来了解更多信息。【参考方案4】:

使用 LayoutManager 平滑滚动

layoutManager.smoothScrollToPosition(recyclerView, new RecyclerView.State(), position);

【讨论】:

【参考方案5】:
final Handler handler = new Handler();
//100ms wait to scroll to item after applying changes
handler.postDelayed(new Runnable() 
@Override
public void run() 
   listView.smoothScrollToPosition(selectedPosition);
, 100);

【讨论】:

他等待 100 毫秒让 recyclerview 完成计算然后进行平滑滚动。你也可以写recyclerView.postDelayed( recyclerView.smoothScrollToPosition(0) , 300)【参考方案6】:

Lars 提到的集合选择方法有效,但动画对于我们的目的来说过于跳跃,因为它跳过了剩下的任何内容。另一种解决方案是重复调用该方法,直到第一个可见位置是您的索引。最好快速完成并且有限制,否则它将与用户滚动视图发生冲突。

private  void DeterminedScrollTo(Android.Widget.ListView listView, int index, int attempts = 0) 
    if (listView.FirstVisiblePosition != index && attempts < 10) 
        attempts++;
        listView.SmoothScrollToPositionFromTop (index, 1, 100);
        listView.PostDelayed (() => 
            DeterminedScrollTo (listView, index, attempts);
        , 100);
    

解决方案是 C# via。 Xamarin 但应该很容易翻译成 Java。

【讨论】:

【参考方案7】:

您在拨打arrayadapter.add() 之后是否拨打arrayadapter.notifyDataSetChanged()?同样可以肯定的是,smoothScrollToPositionsetSelectionListView 中可用的方法,而不是您上面提到的arrayadapter

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

【讨论】:

yea.. 我在论坛这里弄错了,当然是 listview.smoothScrollToPosition(pos) 和 listview.setSelection(pos)。并在调用 arrayadapter.add() 时自动调用 notifyDataSetChanged..,否则 setSelection 将不起作用 很奇怪 setSelection(pos) 可以完美运行,但 smoothScrollToPosition(pos) 不能,不是吗?【参考方案8】:

在android java中使用它,它对我有用:

private void DeterminedScrollTo(int index, int attempts) 
        if (listView.getFirstVisiblePosition() != index && attempts < 10) 
            attempts++;
            if (listView.canScrollVertically(pos))
                listView.smoothScrollToPositionFromTop(index, 1, 200);
            int finalAttempts = attempts;
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() 
                @Override
                public void run() 
                    DeterminedScrollTo(index, finalAttempts);
                
            , 200);
        
    

【讨论】:

【参考方案9】:

kotlin 中的解决方案:

fun AbsListView.scrollToIndex(index: Int, duration: Int = 150) 
    smoothScrollToPositionFromTop(index, 0, duration)
    postDelayed(
        setSelection(index)
        post  smoothScrollToPositionFromTop(index, 0, duration) 
    , duration.toLong())

PS:看起来它在 Android SDK 方面相当混乱,所以如果你不想手动计算视图偏移量,这是你能得到的最好的方法。也许最好的简单方法是将长列表的持续时间设置为 0,以避免任何可见的跳转。

我在 GridView 的某些位置调用 setSelection 时遇到了一些问题,所以在我看来,这确实是一种解决方案,而不是使用它。

【讨论】:

以上是关于android:smoothScrollToPosition() 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )

android 21 是啥版本

Android逆向-Android基础逆向(2-2)

【Android笔记】android Toast

图解Android - Android核心机制

Android游戏开发大全的目录