Android: ScrollView force vers le bas


200

J'aimerais qu'un ScrollView commence tout en bas. Des méthodes?


1
Je pense que c'est juste scrollTo (), oui, je viens de vérifier les documents de développement pour ScrollView. Peasy facile.
Noah Seidman

Réponses:


274

scroll.fullScroll(View.FOCUS_DOWN) devrait également fonctionner.

Mettez cela dans un scroll.Post(Runnable run)

Code Kotlin

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}

6
Cela ne semble rien faire, des suggestions? Je l'ai essayé sur onCreate et plus tard dans le onClick d'un bouton.
RichardJohnn

Cela ne semble pas fonctionner pour changer d'orientation. Sinon, cela fonctionne.
Prashant

1
Cela ne fonctionne pas si la taille de la mise en page a changé juste avant de l'appeler. Il doit être affiché à la place.
MLProgrammer-CiM

2
Ceci et ci-dessous, ne fonctionnera pas jusqu'à ce que vous donniez un certain temps à la vue pour se gonfler complètement, simplifiant simplement la réponse ademar. scrollView.postDelayed (new Runnable () {@Override public void run () {scrollView.fullScroll (View.FOCUS_UP // or Down);}}, 1000);
EngineSense

scroll.fullScroll (View.FOCUS_DOWN) entraînera le changement de focus. Cela apportera un comportement étrange lorsqu'il y a plus d'une vue focalisable, par exemple deux EditText. Vérifiez une autre solution que je propose en bas.
peacepassion

332

vous devez exécuter le code à l'intérieur du scroll.post comme ceci:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});

4
il y a un moyen sans perdre l'élément actuel de focus, quand je fais cela, je perds le focus de mon élément actuel (différent de scrollview)
rkmax

2
Cela n'est nécessaire que dans les cas où la mise en page n'a pas encore été mesurée et mise en page (par exemple si vous l'exécutez dans onCreate). Dans des cas comme appuyer sur un bouton, .post () n'est pas nécessaire.
Patrick Boos

12
Si vous ne voulez pas vous concentrer sur le ScrollView, vous pouvez utiliser scroll.scrollTo(0, scroll.getHeight());pour sauter vers le bas ou scroll.smoothScrollTo(0, scroll.getHeight());pour un défilement plus fluide
yuval

Ce code n'est-il pas une possible fuite de mémoire? Un Runnable anonyme est créé qui contient une référence à une vue d'activité (défilement). Si l'activité est détruite pendant que le runnable exécute sa tâche, il affichera une référence à la vue de défilement, non?
Jenever

A Kotlin:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
Albert Vila Calvo

94

scroll.fullScroll(View.FOCUS_DOWN)entraînera un changement d'orientation. Cela apportera un comportement étrange lorsqu'il y a plusieurs vues focalisables, par exemple deux EditText. Il existe une autre façon de répondre à cette question.

    View lastChild = scrollLayout.getChildAt(scrollLayout.getChildCount() - 1);
    int bottom = lastChild.getBottom() + scrollLayout.getPaddingBottom();
    int sy = scrollLayout.getScrollY();
    int sh = scrollLayout.getHeight();
    int delta = bottom - (sy + sh);

    scrollLayout.smoothScrollBy(0, delta);

Cela fonctionne bien.

Extension Kotlin

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}

Je suis tellement content de ne plus avoir à perdre de temps à ce sujet. Juste ce dont j'avais besoin
Alexandre G

6
Cela devrait avoir plus de votes positifs. C'est de loin la meilleure réponse.
Eric Lange

1
Ceci est la meilleure réponse présente ici.
pointeur vide

1
J'ai essayé tout le reste sur cette page, même en dessous. C'était la seule chose qui a fonctionné, et cela ne fait pas perdre le focus à mon EditText. Je vous remercie.
Joel

Si vous devez faire défiler vers le bas pendant que le clavier s'affiche, combinez ce code avec cette bibliothèque . Fonctionne comme un charme.
wonsuc

47

Parfois, scrollView.post ne fonctionne pas

 scrollView.post(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    });

MAIS si vous utilisez scrollView.postDelayed, cela fonctionnera certainement

 scrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    },1000);

merci pour l'identification. postDelayed est une meilleure solution.
Prashant

@Prashant :) :) :)
Ajay Shrestha

1
N'oubliez pas que vous devez vous débarrasser de votre Runnable lorsque vous avez terminé l'activité
FabioR

38

Ce qui a le mieux fonctionné pour moi, c'est

scroll_view.post(new Runnable() {
     @Override
     public void run() {
         // This method works but animates the scrolling 
         // which looks weird on first load
         // scroll_view.fullScroll(View.FOCUS_DOWN);

         // This method works even better because there are no animations.
         scroll_view.scrollTo(0, scroll_view.getBottom());
     }
});

J'ai essayé cela, mais l'algorithme ici est faux. Vérifiez ma réponse en bas s'il vous plaît.
peacepassion

28

J'incrémente pour travailler parfaitement.

    private void sendScroll(){
        final Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {Thread.sleep(100);} catch (InterruptedException e) {}
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.fullScroll(View.FOCUS_DOWN);
                    }
                });
            }
        }).start();
    }

Remarque

Cette réponse est une solution de contournement pour les versions très anciennes d'Android. Aujourd'hui, postDelayedil n'y a plus de bug et vous devriez l'utiliser.


3
Pas au-dessus de deux, mais cela fonctionne bien dans mon téléphone (LG JellyBean 4.1.2 Optimus G).
Youngjae

9
Pourquoi ne pas utiliser scrollView.postDelayed (exécutable, 100)?
Matt Wolfe

1
@MattWolfe à l'époque ne fonctionnait pas dans certaines anciennes versions d'Android. Mais aujourd'hui, cette réponse est obsolète.
ademar111190

4
Pour l'amour de Dieu, utilisez scrollView.postDelayed (runnable, 100)! :)
Alex Lockwood

1
J'ai ajouté une note @AlexLockwood J'espère que les gens utiliseront le postDelayed:)
ademar111190

4

j'ai essayé avec succès.

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);

3

Lorsque la vue n'est pas encore chargée, vous ne pouvez pas faire défiler. Vous pouvez le faire «plus tard» avec un post ou un appel de sommeil comme ci-dessus, mais ce n'est pas très élégant.

Il est préférable de planifier le défilement et de le faire lors du prochain onLayout (). Exemple de code ici:

https://stackoverflow.com/a/10209457/1310343


3

Une chose à considérer est ce qu'il ne faut PAS définir. Assurez-vous que vos contrôles enfants, en particulier les contrôles EditText, n'ont pas la propriété RequestFocus définie. Il peut s'agir de l'une des dernières propriétés interprétées de la disposition et elle remplacera les paramètres de gravité de ses parents (la disposition ou ScrollView).


3

Voici quelques autres façons de défiler vers le bas

fun ScrollView.scrollToBottom() {
    // use this for scroll immediately
    scrollTo(0, this.getChildAt(0).height) 

    // or this for smooth scroll
    //smoothScrollBy(0, this.getChildAt(0).height)

    // or this for **very** smooth scroll
    //ObjectAnimator.ofInt(this, "scrollY", this.getChildAt(0).height).setDuration(2000).start()
}

En utilisant

Si vous faites défiler la vue déjà présentée

my_scroll_view.scrollToBottom()

Si votre vue de défilement n'est pas terminée (par exemple: vous faites défiler vers le bas dans la onCreateméthode d' activité ...)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}

1

Pas exactement la réponse à la question, mais je devais faire défiler vers le bas dès qu'un EditText avait le focus. Cependant, la réponse acceptée ferait perdre également la focalisation à l'ET (pour ScrollView, je suppose).

Ma solution de contournement était la suivante:

emailEt.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus){
            Toast.makeText(getActivity(), "got the focus", Toast.LENGTH_LONG).show();
            scrollView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scrollView.fullScroll(ScrollView.FOCUS_DOWN);
                }
            }, 200);
        }else {
            Toast.makeText(getActivity(), "lost the focus", Toast.LENGTH_LONG).show();
        }
    }
});

1

En fait, j'ai trouvé qu'appeler fullScroll deux fois fait l'affaire:

myScrollView.fullScroll(View.FOCUS_DOWN);

myScrollView.post(new Runnable() {
    @Override
    public void run() {
        myScrollView.fullScroll(View.FOCUS_DOWN);
    }
});

Cela peut avoir quelque chose à voir avec l'activation de la méthode post () juste après avoir effectué le premier défilement (infructueux). Je pense que ce problème se produit après tout appel de méthode précédent sur myScrollView, vous pouvez donc essayer de remplacer la première méthode fullScroll () par toute autre chose qui pourrait vous concerner.


0

Il existe une autre façon intéressante de le faire avec les coroutines Kotlin. L'avantage d'utiliser une coroutine opposée à un gestionnaire avec un exécutable (post / postDelayed) est qu'il ne lance pas un thread coûteux pour exécuter une action différée.

launch(UI){
    delay(300)
    scrollView.fullScroll(View.FOCUS_DOWN)
}

Il est important de spécifier le HandlerContext de la coroutine comme interface utilisateur, sinon l'action différée risque de ne pas être appelée à partir du thread d'interface utilisateur.


0

Dans ces cas, l'utilisation de scroll.scrollTo (0, sc.getBottom ()) ne fonctionnait pas, utilisez-la en utilisant scroll.post

Exemple:

scroll.post(new Runnable() {
  @Override
  public void run() {
  scroll.fullScroll(View.FOCUS_DOWN);
  } 
});

0

Une des raisons possibles pour lesquelles cela scroll.fullScroll(View.FOCUS_DOWN)pourrait ne pas fonctionner même enveloppé .post()est que la vue n'est pas disposée. Dans ce cas, View.doOnLayout () pourrait être une meilleure option:

scroll.doOnLayout(){
    scroll.fullScroll(View.FOCUS_DOWN)
}

Ou, quelque chose de plus élaboré pour les âmes courageuses: https://chris.banes.dev/2019/12/03/suspending-views/

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.