Comment faire défiler vers le haut d'une longue mise en page ScrollView?

162

Pour une partie de mon application, l'utilisateur reçoit une liste de noms et est invité à les regrouper comme il l'entend.

(Notez que le code ListView a été copié textuellement à partir du didacticiel Android Views. Je ne l'ai pas encore personnalisé en fonction de mes besoins, j'essaie simplement de comprendre comment faire fonctionner 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 ma ListView en dessous, qui affiche la liste des noms. Tout cela est plus grand que la zone d'écran visible, de sorte que l'utilisateur est autorisé à faire défiler verticalement pour tout voir.

Tout cela fonctionne à merveille, sauf lorsque la page se charge, elle est toujours pré-défilée vers le haut de ma ListView - au milieu de la page. Le texte et les boutons que j'ai créés qui indiquent à l'utilisateur quoi faire ne sont pas visibles.

Je peux saisir l'écran et faire défiler vers le haut, cela fonctionne très bien, mais j'aimerais que l'écran se charge après avoir déjà été défilé vers le haut. L'utilisateur ne devrait pas avoir à faire défiler vers le HAUT pour voir le haut d'une page fraîchement chargée. Mais tout ce que j'ai essayé de faire défiler par programme vers le haut de l'écran 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.

Comme 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 ScrollView ou RelativeLayout qui le contient. Ceci semble être confirmé par la propre description de Google de la méthode scrollTo (int x, int y) où ils disent "Cette version limite également le défilement aux limites de notre enfant.".

Donc, pour prolonger encore une longue question, comment charger un groupe de vues sur l'écran contenues dans un ScrollView, puis faire défiler le tout par programme vers le haut de la page afin que l'utilisateur puisse interagir avec lui?

Merci!

Glenn
la source

Réponses:

264

Essayer

mainScrollView.fullScroll(ScrollView.FOCUS_UP);

ça devrait marcher.

Roomtek
la source
Fonctionne aussi pour moi. : D
Muntasir Aonik
1
J'ai trouvé que ScrollView # fullScroll () change le focus actuel. J'ai testé avec EditText.
illusionJJ
175

Eu le même problème, probablement une sorte de bogue.

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

Mohamed Hafez
la source
Cela a fonctionné au début, mais plus tard, quand j'ai essayé de le faire encore et encore, cette approche n'a pas donné de résultat satisfaisant.
JaydeepW
16
Je résolve à partir de scroll_view.smoothScrollTo (0,0), lorsque nous avons listview à côté, le scrollview à ce moment-là fullScroll (ScrollView.FOCUS_UP) ne fonctionnera pas.
Kirtikumar A.
1
scroll_view.smoothScrollTo (0,0) fonctionnait mieux pour moi que mainScrollView.fullScroll (ScrollView.FOCUS_UP); MERCI!
marienke
2
Sur la plupart des appareils, fullScroll (ScrollView.FOCUS_UP) fonctionnait, mais sur le Nexus 5 et les appareils où la taille du texte était augmentée - le fullSscroll déplacé sous la barre d'action, smoothScrollTo (0,0) fonctionnait mieux sur tous les appareils.
jt-gilkeson
Cela présente également l'avantage fullScroll()de conserver l'élément sélectionné toujours sélectionné après le déplacement. Avec fullScroll(), le premier élément de la vue par défilement a été resélectionné à chaque fois dans mon cas, indépendamment de l'élément sélectionné avant que le défilement ne se déplace vers le haut.
GeertVc
97

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

listView.setFocusable(false);
Miguel Palacios
la source
3
C'est également la bonne solution pour les vues en grille. Cela se produit lorsque vous avez plusieurs éléments de vue dans le même groupe de vues, en particulier une autre vue de liste en haut de la liste ou de la grille. Étant donné que l'adaptateur notifie le thread d'interface utilisateur, la vue est recréée et défile jusqu'au premier élément. Appelez simplement listView.setFocusable (false) / gridView.setFocusable (false). Si vous le faites à partir d'un fichier xml, cela ne fonctionnera pas.
omersem
Cette solution a également fonctionné dans mon cas, j'avais RecyclerView à l'intérieur de NestedScrollView, donc il faisait défiler automatiquement vers le bas. Merci mec!
Nilesh Rathore
J'ai dû ajouter ceci avant de régler l'adaptateur, mais après cela fonctionne comme un charme. Merci
Communauté
explication parfaite !!
Borja López
Merci à Miguel et en particulier à omersem pour l'explication, en particulier la partie sur la façon dont cela ne fonctionnera pas s'il est défini en XML, cela m'a évité quelques maux de tête
buradd
53

scrollViewObject.fullScroll(ScrollView.FOCUS_UP)cela fonctionne bien, mais seul le problème avec cette ligne est que, lorsque les données se remplissent dans scrollViewObject, a été 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);
    }
});
Mohammad Imran
la source
Je faisais face au même problème où la vue de défilement était censée défiler vers le bas de la page, je l'ai corrigée!
Machine Tribe
1
Au lieu de deviner le nombre "magique" x de millisecondes que vous auriez à attendre, les objets View offrent une méthode de publication (exécutable) que vous pouvez utiliser et qui publiera le fichier exécutable une fois que le widget sera rendu sur l'interface utilisateur.
Ryan
@Ryan: post (Runnable) ne fonctionne toujours pas pour moi sur Nexus 5 (Genymotion)
Dika
post (Runnable) peut ne pas fonctionner car si vous récupérez des données après l'étape d'infloation de la vue, le premier défilement fonctionne, puis les données sont remplies dans la vue. Vous devez donc soit utiliser postDelayed (Runnable, dummyMillis), soit utiliser scroll.fullScroll (ScrollView.FOCUS_UP) après les processus remplis de données.
oguzhan
Votre première solution dans laquelle vous donnez des millis statiques est une mauvaise approche.
Malwinder Singh
35

Le principal problème de toutes ces solutions valables est que vous essayez de remonter le rouleau lorsqu'il n'est pas encore dessiné à l'écran.

Vous devez attendre que la vue de défilement s'affiche à l'écran, puis la déplacer vers le haut avec l'une de ces solutions. C'est une meilleure solution qu'un post-délai, car cela ne vous dérange pas.

    // Wait until my scrollView is ready
    scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // Ready, move up
            scrollView.fullScroll(View.FOCUS_UP);
        }
    });
Pélanes
la source
7
Belle solution - N'oubliez pas de supprimer le Global Listener à la fin de l' onGlobalLayoutappel de la méthode scrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Nilhcem
30

Très facile

    ScrollView scroll = (ScrollView) findViewById(R.id.addresses_scroll);
    scroll.setFocusableInTouchMode(true);
    scroll.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
CommonSenseCode
la source
3
pour moi cela n'a pas fonctionné (la 3ème ligne), la solution était: scroll.fullScroll (View.FOCUS_UP); (en incluant vos 2 premières lignes)
medskill
@medskill, Salut, les avez-vous écrites dans votre fichier xml? Je pense que cela ne fonctionne que dans onCreate().
imknown
@ imknownJ.Kimu Fonctionne pour moi dans un fichier xml
Paglian
Cela a fonctionné pour moi. Vous avez besoin de la deuxième et de la troisième ligne. Cela ne fonctionnerait pas dans le XML pour moi.
ET
2
Je t'embrasserais si je le pouvais! J'ai passé 1 à 2 heures là-dessus. Le meilleur en attendant le chargement de deux vues de liste et ne voulant pas se concentrer sur elles. Ajouté à onResume ().
John T
24

J'ai rencontré le même problème lorsque j'utilise Scrollview dans View Flipper ou Dialog, ce cas scrollViewObject.fullScroll(ScrollView.FOCUS_UP)retourne false de sorte que le cas scrollViewObject.smoothScrollTo(0, 0)est travaillé pour moi

Faire défiler le focus vers le haut

sravan
la source
19
 final ScrollView scrollview = (ScrollView)findViewById(R.id.selected_place_layout_scrollview);

         scrollview.post(new Runnable() { 
                public void run() { 
                    scrollview.scrollTo(0, 0); 
                } 
            }); 
Mladen Rakonjac
la source
9
runOnUiThread( new Runnable(){
   @Override
   public void run(){
      mainScrollView.fullScroll(ScrollView.FOCUS_UP);
   }
}
traeper
la source
9

Cela a fonctionné pour moi

scroll_view.smoothScrollTo(0,0); // scroll to top of screen
Pankaj Talaviya
la source
6

Ceci est le défilement forcé pour le scrollview :

            scrollView.post(new Runnable() {
                @Override
                public void run() {
                    scrollView.scrollTo(0, 0);
                    scrollView.pageScroll(View.FOCUS_UP);
                    scrollView.smoothScrollTo(0,0);
                }
            });
Hadi Note
la source
4
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // Ready, move up
        scrollView.fullScroll(View.FOCUS_UP);
    }
});

la source
1

J'ai résolu mon problème dans Kotlin comme ceci:

scrollview.isFocusableInTouchMode = true
scrollview.fullScroll(View.FOCUS_UP)
scrollview.smoothScrollTo(0,0)
MaK
la source
0
@SuppressWarnings({ "deprecation", "unchecked" })
public void swipeTopToBottom(AppiumDriver<MobileElement> driver) 
                    throws InterruptedException {
       Dimension dimensions = driver.manage().window().getSize();
        Double screenHeightStart = dimensions.getHeight() * 0.30;
        int scrollStart = screenHeightStart.intValue();
        System.out.println("s="+scrollStart);
        Double screenHeightEnd = dimensions.getHeight()*0.90;
        int scrollEnd = screenHeightEnd.intValue();
        driver.swipe(0,scrollStart,0,scrollEnd,2000);
        CommonUtils.threadWait(driver, 3000);
    }
Ajeet Gour
la source
cela fonctionnera à coup sûr,
Ajeet Gour
Veuillez expliquer brièvement comment cette réponse résout le problème.
Ayberk Özgür