Android: smoothScrollToPosition () работает неправильно

Я пытаюсь сгладить прокрутку до последнего элемента списка после добавления элемента в arrayadapter, связанный с listview. Проблема в том, что он просто прокручивается до произвольной позиции

arrayadapter.add(item); //DOES NOT WORK CORRECTLY: listview.smoothScrollToPosition(arrayadapter.getCount()-1); //WORKS JUST FINE: listview.setSelection(arrayadapter.getCount()-1); 

    Вероятно, вы хотите, чтобы ListView опубликовал прокрутку, когда поток пользовательского интерфейса может обрабатывать его (вот почему вы не прокручиваете его правильно). SmoothScroll должен выполнять большую работу, а не просто идти в позицию, игнорируя скорость / время / и т. Д. (Требуется для «анимации»).

    Поэтому вы должны сделать что-то вроде:

      getListView().post(new Runnable() { @Override public void run() { getListView().smoothScrollToPosition(pos); } }); 

    (Скопировано из моего ответа: smoothScrollToPositionFromTop () не всегда работает так, как должно )

    Это известная ошибка. См. 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; } } 

    Вы должны использовать метод setSelection ().

    Метод выбора набора, упомянутый Ларсом, работает, но анимация была слишком нервной для наших целей, поскольку она пропускает все, что осталось. Другим решением является повторный вызов метода до тех пор, пока первая видимая позиция не станет вашим индексом. Это лучше всего сделать быстро и с лимитом, так как это будет бороться с прокруткой пользователя в противном случае.

     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 # через. Xamarin, но должен легко перевестись на Java.

    Вы вызываете arrayadapter.notifyDataSetChanged() после arrayadapter.add() ? Также, конечно, smoothScrollToPosition и setSelection – это методы, доступные в ListView не arrayadapter как вы уже упоминали выше.

    В любом случае посмотрите, поможет ли это: smoothScrollToPosition после notifyDataSetChanged не работает в android

     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);