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!

Réponses:


264

Essayer

mainScrollView.fullScroll(ScrollView.FOCUS_UP);

ça devrait marcher.


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.


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);

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

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

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);

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


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

         scrollview.post(new Runnable() { 
                public void run() { 
                    scrollview.scrollTo(0, 0); 
                } 
            }); 

9
runOnUiThread( new Runnable(){
   @Override
   public void run(){
      mainScrollView.fullScroll(ScrollView.FOCUS_UP);
   }
}

9

Cela a fonctionné pour moi

scroll_view.smoothScrollTo(0,0); // scroll to top of screen

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

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

1

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

scrollview.isFocusableInTouchMode = true
scrollview.fullScroll(View.FOCUS_UP)
scrollview.smoothScrollTo(0,0)

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

cela fonctionnera à coup sûr,
Ajeet Gour

Veuillez expliquer brièvement comment cette réponse résout le problème.
Ayberk Özgür
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.