Aleksey Malevaniy Aleksey Malevaniy - 1 month ago 7
Android Question

Wait unitl ListView's smoothScrollToPosition() finishes

Scope



I need to scroll to certain position smoothly and then "jump" to another position with
setSelection(anotherPosition)
. This is done to create an illusion of smooth scrolling of (e.g.) 100 items in
ListView
.
smoothScrollToPosition(100)
lasts too much, you know.

Problem



setSelection()
doesn't wait till
smoothScrollToPositio
n finishes its work, so
setSelection()
is being called immediately and user sees quick jumping only;

Code



private final int scrollableItems = 20;

int firstVisiblePosition = mListView.getFirstVisiblePosition();
if (firstVisiblePosition < scrollableItems) {
mListView.smoothScrollToPosition(0);
} else {
mListView.smoothScrollToPosition(firstVisiblePosition - scrollableItems);
mListView.setSelection(0);
}
mListView.clearFocus();


Idea



OK, we could change logic of smoothness illusion: first
setSelection()
, then scroll smoothly (we're scrolling to the very first item on top of the list):

int firstVisiblePosition = mListView.getFirstVisiblePosition();

if (firstVisiblePosition < scrollableItems) {
mListView.smoothScrollToPosition(0);
} else {
mListView.setSelection(scrollableItems);
mListView.smoothScrollToPosition(0);
}
mListView.clearFocus();

Answer
final ListView listView = ...;
View listItemView = ...;
listView.smoothScrollBy(listItemView.getHeight() * NUMBER_OF_VIEWS, 
    DURATION * 2);
listView.postDelayed(new Runnable() {
    public void run() {
        listView.smoothScrollBy(0, 0); // Stops the listview from overshooting.
        listView.setSelection(0);
    }
}, DURATION);

Of course, direction of the scroll etc. would need to be adjusted for your use case (go to the top of the list)

EDIT: Old solution could overshoot if the velocity of the scroll was too high, smoothScrollBy(0,0) will stop the smooth scrolling before setting the selection properly and immediately.

Comments