Android: ScrollView force vers le bas

200

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

Noah Seidman
la source
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)
}
CommonsWare
la source
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);              
    }
});
hungson175
la source
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)
}
peacepassion
la source
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);
Ajay Shrestha
la source
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());
     }
});
https
la source
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.

ademar111190
la source
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);
Yusuf Yaşar
la source
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

Franc
la source
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).

Epsilon3
la source
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()          
}
Phan Van Linh
la source
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();
        }
    }
});
Teo Inke
la source
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.

BarLr
la source
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.

Phaestion
la source
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);
  } 
});
nnyerges
la source
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/

Ghedeon
la source