これは既知のバグです。https://code.google.com/p/android/issues/detail?id=36062を参照してください
ただし、発生する可能性のあるすべてのエッジケースに対処するこの回避策を実装しました。
最初に を呼び出しsmothScrollToPositionFromTop(position)
、スクロールが終了したら を呼び出しますsetSelection(position)
。後者の呼び出しは、目的の位置に直接ジャンプすることにより、不完全なスクロールを修正します。そうすることで、ユーザーはまだこの位置までアニメーションでスクロールされているという印象を受けます。
この回避策を 2 つのヘルパー メソッド内に実装しました。
SmoothScrollToPositionFromTop()
public static void smoothScrollToPositionFromTop(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;
}
}