179 votes

Comment faire défiler en haut d'une longue présentation ScrollView ?

Pour une partie de mon application, l'utilisateur se voit présenter une liste de noms et est invité à les regrouper comme il l'entend.

(Remarque : le code du ListView a été copié mot pour mot du tutoriel Android Views. Je ne l'ai pas encore adapté à mes besoins, j'essaie juste de comprendre comment faire fonctionner tout cela).

La disposition de base est un LinearLayout, contenant un ScrollView (appelé "groupsScrollView" dans le code ci-dessous), contenant un RelativeLayout. J'ai quelques boutons et du texte, puis mon ListView en dessous, qui affiche la liste des noms. Tout cela est plus haut que la zone visible de l'écran, ce qui permet à l'utilisateur de faire défiler l'écran verticalement pour tout voir.

Tout cela fonctionne à merveille, sauf que lorsque la page se charge, elle est toujours pré-défilée en haut de mon ListView - au milieu de la page. Le texte et les boutons que j'ai créés pour indiquer à l'utilisateur ce qu'il doit faire ne sont pas visibles.

Je peux saisir l'écran et le faire défiler vers le haut, cela fonctionne très bien, mais j'aimerais que l'écran se charge en ayant déjà été défilé vers le haut. L'utilisateur ne devrait pas avoir à faire défiler l'écran vers le HAUT pour voir le haut d'une page fraîchement chargée. Mais tout ce que j'ai essayé pour faire défiler l'écran jusqu'en haut de façon programmatique a échoué.

Voici ma méthode onCreate :

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.groups);

    mainScrollView = (ScrollView)findViewById(R.id.groupsScrollView);

    //get the Bundle out of the Intent...
    Bundle extras = getIntent().getExtras();
    mNames = extras.getStringArray("mNames");

    setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, mNames));

    ListView lv = getListView();
    lv.setTextFilterEnabled(true);

    //This is the line I'm having issues with
    mainScrollView.pageScroll(View.FOCUS_UP);

    lv.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
            int position, long id) {
          // When clicked, show a toast with the TextView text
          Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
              Toast.LENGTH_SHORT).show();
        }
      });
}

La ligne "mainScrollView.pageScroll(View.FOCUS_UP) ; est le problème. Elle ne provoque pas d'erreur, mais elle ne semble rien faire. J'ai essayé scrollTo(0,0), scrollDirection(View.FOCUS_UP), et tout ce à quoi je peux penser.

Puisque je n'obtiens pas d'erreur, je dois supposer que ces commandes de défilement fonctionnent réellement, mais qu'elles défilent vers le haut de la ListView, plutôt que vers le haut de la ScrollView ou du RelativeLayout qui la contient. Cela semble être confirmé par la propre description de Google de la méthode scrollTo(int x, int y), où il est dit que "Cette version fixe également le défilement aux limites de notre enfant".

Donc, pour rendre une longue question encore plus longue, comment puis-je charger un ensemble de vues à l'écran contenues dans un ScrollView, puis faire défiler le tout de manière programmatique en haut de la page pour que l'utilisateur puisse interagir avec lui ?

Merci !

288voto

roomtek Points 1088

Essayez

mainScrollView.fullScroll(ScrollView.FOCUS_UP);

cela devrait fonctionner.

0 votes

Ça marche pour moi aussi. :D

1 votes

J'ai trouvé que ScrollView#fullScroll() change le focus actuel. J'ai testé avec EditText.

183voto

Mohamed Hafez Points 1979

J'ai eu le même problème, probablement une sorte de bug.

Même le fullScroll(ScrollView.FOCUS_UP) de l'autre réponse n'a pas fonctionné.
La seule chose qui a fonctionné pour moi a été d'appeler scroll_view.smoothScrollTo(0,0) juste après l'affichage de la boîte de dialogue.

0 votes

Cela a fonctionné dans un premier temps, mais plus tard, lorsque j'ai essayé de le refaire encore et encore, cette approche n'a pas donné de résultat satisfaisant.

16 votes

J'ai résolu le problème à partir de scroll_view.smoothScrollTo(0,0), lorsque nous avons une vue de liste à côté de la vue de défilement à ce moment-là fullScroll(ScrollView.FOCUS_UP) ne fonctionnera pas.

1 votes

Scroll_view.smoothScrollTo(0,0) a mieux fonctionné pour moi que mainScrollView.fullScroll(ScrollView.FOCUS_UP) ; MERCI !

100voto

Miguel Palacios Points 31

J'ai eu le même problème et cela l'a réglé. J'espère que cela vous aidera.

listView.setFocusable(false);

3 votes

C'est la solution correcte pour les gridviews également. Cela se produit lorsque vous avez plus d'un élément de vue dans le même groupe de vues, en particulier un autre listview au-dessus de la liste ou du gridview. Comme l'adaptateur notifie le thread UI, la vue est recréée et défile jusqu'au premier élément. Il suffit d'appeler listView.setFocusable(false) / gridView.setFocusable(false). Si vous le faites à partir du fichier xml, cela ne fonctionnera pas.

0 votes

Cette solution a également fonctionné dans mon cas, j'avais RecyclerView à l'intérieur de NestedScrollView de sorte qu'il y avait un défilement automatique vers le bas. Merci !

1 votes

J'ai dû l'ajouter avant de définir l'adaptateur, mais après cela, ça marche comme sur des roulettes. Merci

59voto

Mohammad Imran Points 938

scrollViewObject.fullScroll(ScrollView.FOCUS_UP) Cela fonctionne bien, mais le seul problème avec cette ligne est que, lorsque les données sont remplies dans scrollViewObject, elle est appelée immédiatement. Vous devez attendre quelques millisecondes jusqu'à ce que les données soient remplies. Essayez ce code :

scrollViewObject.postDelayed(new Runnable() {
    @Override
    public void run() {
        scroll.fullScroll(ScrollView.FOCUS_UP);
    }
}, 600);

OU

 scrollViewObject.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        scrollViewObject.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        scrollViewObject.fullScroll(View.FOCUS_UP);
    }
});

0 votes

J'avais le même problème où le scrollview était censé défiler jusqu'au bas de la page, cela a été corrigé !

1 votes

Au lieu de deviner le nombre "magique" de millisecondes à attendre, les objets View offrent une méthode post(Runnable) que vous pouvez utiliser pour afficher le runnable une fois le widget rendu sur l'interface utilisateur.

0 votes

@Ryan : post(Runnable) ne fonctionne toujours pas pour moi sur Nexus 5 (Genymotion)

36voto

Pelanes Points 744

Le principal problème de toutes ces solutions valables est que vous essayez de faire avancer le défilement alors qu'il n'est pas encore dessiné à l'écran.

Vous devez attendre que la vue défilante soit à l'écran, puis la déplacer vers le haut avec l'une de ces solutions. C'est une meilleure solution qu'un postdelay, car vous ne vous souciez pas du délai.

    // Wait until my scrollView is ready
    scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // Ready, move up
            scrollView.fullScroll(View.FOCUS_UP);
        }
    });

7 votes

Belle solution - N'oubliez pas de supprimer le Global Listener à la fin de l'opération. onGlobalLayout appel de méthodes scrollView.getViewTreeObserver().removeOnGlobalLayoutListene‌​r(this);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X