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()
?同样可以肯定的是,smoothScrollToPosition
和setSelection
是ListView
中可用的方法,而不是您上面提到的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 用户权限 )