android: smoothscrolltopposition () ne fonctionne pas correctement

j'essaie de faire défiler en douceur le dernier élément d'une liste après avoir ajouté un élément au tableau associé à listview. Le problème est qu'il ne fait que défiler vers une position aléatoire

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

//WORKS JUST FINE:
listview.setSelection(arrayadapter.getCount()-1);
43
demandé sur user1515520 2012-07-11 15:38:37

6 réponses

vous voulez probablement dire au ListView de poster le scroll lorsque le thread de L'interface utilisateur peut le gérer (c'est pourquoi le vôtre ne le fait pas défiler correctement). SmoothScroll besoin de faire beaucoup de travail, plutôt que de simplement aller à une position ignorant vitesse/temps/etc. (requis pour une "animation").

donc vous devriez faire quelque chose comme:

    getListView().post(new Runnable() {
        @Override
        public void run() {
            getListView().smoothScrollToPosition(pos);
        }
    });
53
répondu Martin Marconcini 2013-08-08 18:23:10

(copié de ma réponse: smoothscrolltoppositionfromtop () ne fonctionne pas toujours comme il se doit )

c'est un bug connu. voir https://code.google.com/p/android/issues/detail?id=36062

cependant, j'ai mis en œuvre Cette solution qui traite de tous les cas de bordures qui pourraient se produire:

premier appel smothScrollToPositionFromTop(position) et puis, lorsque le défilement a terminé, appelez setSelection(position) . Ce dernier appel corrige le défilement incomplet en sautant directement à la position désirée. Ce faisant, l'Utilisateur a encore l'impression qu'il est en train d'être animé-scrolled à cette position.

j'ai mis en œuvre Cette solution dans deux méthodes d'aide:

smoothscrolltopposition ()

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;
    }
}
11
répondu Lars Blumberg 2015-08-18 14:24:43

vous devez utiliser la méthode setSelection ().

5
répondu TaoZang 2012-09-27 07:48:19

la méthode de sélection de set mentionnée par Lars fonctionne, mais l'animation était trop sautillante pour nos besoins car elle sautait tout ce qui restait. Une autre solution est de rappeler la méthode à plusieurs reprises jusqu'à ce que la première position visible soit votre index. Cela est mieux fait rapidement et avec une limite car il combattra l'utilisateur défilant la vue autrement.

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);
    }
}
La Solution

est en C# via. Xamarin mais devrait traduire facilement en Java.

2
répondu Daniel Roberts 2015-09-17 10:26:20

appelez-vous arrayadapter.notifyDataSetChanged() après avoir appelé arrayadapter.add() ? Aussi pour être sûr, smoothScrollToPosition et setSelection sont des méthodes disponibles dans ListView et non arrayadapter comme vous avez mentionné ci-dessus.

dans tous les cas voir si cela aide: smoothscrolltopposition after notifydatase modified not working in android

1
répondu Code Poet 2017-05-23 12:18:17
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);
1
répondu VSB 2016-05-27 20:38:12