在将元素添加到与列表视图关联的数组适配器后,我试图平滑滚动到列表的最后一个元素。问题是它只是滚动到一个随机位置
arrayadapter.add(item);
//DOES NOT WORK CORRECTLY:
listview.smoothScrollToPosition(arrayadapter.getCount()-1);
//WORKS JUST FINE:
listview.setSelection(arrayadapter.getCount()-1);
在将元素添加到与列表视图关联的数组适配器后,我试图平滑滚动到列表的最后一个元素。问题是它只是滚动到一个随机位置
arrayadapter.add(item);
//DOES NOT WORK CORRECTLY:
listview.smoothScrollToPosition(arrayadapter.getCount()-1);
//WORKS JUST FINE:
listview.setSelection(arrayadapter.getCount()-1);
您可能想告诉 ListView 在 UI 线程可以处理它时发布滚动(这就是您的滚动不正确的原因)。SmoothScroll 需要做很多工作,而不是仅仅去一个忽略速度/时间/等的位置。(对于“动画”是必需的)。
因此,您应该执行以下操作:
getListView().post(new Runnable() {
@Override
public void run() {
getListView().smoothScrollToPosition(pos);
}
});
(Copied from my answer: smoothScrollToPositionFromTop() is not always working like it should)
This is a known bug. See https://code.google.com/p/android/issues/detail?id=36062
However, I implemented this workaround that deals with all edge cases that might occur:
First call smothScrollToPositionFromTop(position)
and then, when scrolling has finished, call setSelection(position)
. The latter call corrects the incomplete scrolling by jumping directly to the desired position. Doing so the user still has the impression that it is being animation-scrolled to this position.
I implemented this workaround within two helper methods:
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;
}
}
您应该使用 setSelection() 方法。
使用 LayoutManager 平滑滚动
layoutManager.smoothScrollToPosition(recyclerView, new RecyclerView.State(), position);
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);
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。
你打电话arrayadapter.notifyDataSetChanged()
后打电话arrayadapter.add()
吗?也可以肯定的是,smoothScrollToPosition
这些setSelection
方法ListView
不是arrayadapter
你上面提到的。
无论如何,看看这是否有帮助: notifyDataSetChanged not working in android after smoothScrollToPosition
在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);
}
}
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 时我遇到了一些问题,所以在我看来,这确实是解决方案,而不是使用它。