15

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 smoothScrollToPosition 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();
Community
  • 1
  • 1
Oleksii Malovanyi
  • 6,780
  • 6
  • 24
  • 27

2 Answers2

24
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.

Jens
  • 16,853
  • 4
  • 55
  • 52
  • But it could be a solution only for list with fixed height items. I think that mListView.setSelection(scrollableItems); mListView.smoothScrollToPosition(0); is still more preferable way ;) – Oleksii Malovanyi Oct 28 '11 at 13:23
  • Yup, its only used to get a suitably high speed. As long as you replace the height * NUMBER_OF_VIEWS with any other suitably large value (i.e. if your views are very varied in size) you will get a fast enough scroll that the user wont notice when you snap with setSelection(0) in the Runnable that is postDelayed to the ListView. – Jens Oct 28 '11 at 13:28
0

Another way is to add an OnScrollListener.

private final int scrollableItems = 20;

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

    mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
      @Override
      public void onScrollStateChanged(AbsListView absListView, int i) {
        if (i == SCROLL_STATE_IDLE) {
          mListView.setSelection(0);
           }
      }
   })

   mListView.smoothScrollToPosition(firstVisiblePosition - scrollableItems);
}
mListView.clearFocus();
Jeff Padgett
  • 2,380
  • 22
  • 34