Puis-je faire défiler un ScrollView par programmation dans Android?

145

Existe-t-il un moyen de faire défiler un ScrollViewprogramme vers une certaine position?

J'ai créé une dynamique TableLayoutqui est placée dans un fichier ScrollView. Donc, je veux que sur une action spécifique (comme cliquer sur un bouton, etc.) la ligne particulière devrait défiler automatiquement vers une position supérieure.

C'est possible?

Arun Badole
la source

Réponses:

165
ScrollView sv = (ScrollView)findViewById(R.id.scrl);
sv.scrollTo(0, sv.getBottom());

ou

sv.scrollTo(5, 10);

Android
la source
43
En combinant la réponse d'ercu et un commentaire qui y est fait, le meilleur moyen semble être:mScrollView.post(new Runnable() { public void run() { mScrollView.fullScroll(View.FOCUS_DOWN); } });
sparrowt
2
scrollTo () ne produira pas le résultat souhaité. On devrait aller avec fullScroll ()
Amit Yadav
3
Un plus beau défilement est avec un effet naturel: sv.smoothScrollTo (5, 10)
ivan.panasiuk
205

La réponse de Pragna ne fonctionne pas toujours, essayez ceci:

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

ou

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.fullScroll(mScrollView.FOCUS_DOWN);
        } 
});

si vous voulez faire défiler pour commencer

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.fullScroll(mScrollView.FOCUS_UP);
        } 
});
ercu
la source
28
Je l'ai utilisé mScrollView.fullScroll(mScrollView.FOCUS_DOWN);avec succès.
amcc
3
Je peux confirmer les conclusions de Vanthel. mScrollView.fullScroll dans un post exécutable a fait l'affaire.
AlanKley
1
Excellent! En effet, sans le Runnable, cela ne fonctionnait pas. Maintenant ça marche ! :)
Regis_AG
5
@HiteshDhamshaniya Si vous voulez un défilement fluide, essayez mScrollView.smoothScrollTo(0, mScrollView.getBottom());.
Mike Ortiz
1
Pourquoi a-t-il besoin postici?
Liuting
35

Je voulais que scrollView défile directement après onCreateView () (pas après par exemple un clic sur un bouton). Pour le faire fonctionner, j'avais besoin d'utiliser un ViewTreeObserver:

mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mScrollView.post(new Runnable() {
                public void run() {
                    mScrollView.fullScroll(View.FOCUS_DOWN);
                }
            });
        }
    });

Mais attention, cela sera appelé à chaque fois que quelque chose sera mis en page (par exemple si vous définissez une vue invisible ou similaire), alors n'oubliez pas de supprimer cet écouteur si vous n'en avez plus besoin avec:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) sur SDK Lvl <16

ou

public void removeOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) dans SDK Lvl> = 16

Patrick Favre
la source
23

Il y a beaucoup de bonnes réponses ici, mais je veux seulement ajouter une chose. Il arrive parfois que vous souhaitiez faire défiler votre ScrollView vers une vue spécifique de la mise en page, au lieu d'un défilement complet vers le haut ou le bas.

Un exemple simple: dans un formulaire d'inscription, si l'utilisateur appuie sur le bouton "Inscription" alors qu'un texte d'édition du formulaire n'est pas rempli, vous voulez faire défiler jusqu'à ce texte d'édition spécifique pour indiquer à l'utilisateur qu'il doit remplir ce champ.

Dans ce cas, vous pouvez faire quelque chose comme ça:

scrollView.post(new Runnable() { 
        public void run() { 
             scrollView.scrollTo(0, editText.getBottom());
        } 
});

ou, si vous voulez un défilement fluide au lieu d'un défilement instantané:

scrollView.post(new Runnable() { 
            public void run() { 
                 scrollView.smoothScrollTo(0, editText.getBottom());
            } 
    });

Évidemment, vous pouvez utiliser n'importe quel type de vue au lieu de Modifier le texte. Notez que getBottom () renvoie les coordonnées de la vue en fonction de sa disposition parente, de sorte que toutes les vues utilisées à l'intérieur de ScrollView ne doivent avoir qu'un parent (par exemple une disposition linéaire).

Si vous avez plusieurs parents dans l'enfant du ScrollView, la seule solution que j'ai trouvée est d'appeler requestChildFocus sur la vue parent:

editText.getParent().requestChildFocus(editText, editText);

mais dans ce cas, vous ne pouvez pas avoir un défilement fluide.

J'espère que cette réponse peut aider quelqu'un avec le même problème.

Mattia Ruggiero
la source
1
@JohnT Heureux que cela vous ait aidé :)
Mattia Ruggiero
20

Utilisez quelque chose comme ceci:

mScrollView.scrollBy(10, 10);

ou

mScrollView.scrollTo(10, 10);
Srichand Yella
la source
8

Si vous souhaitez faire défiler instantanément, vous pouvez utiliser:

ScrollView scroll= (ScrollView)findViewById(R.id.scroll);
scroll.scrollTo(0, scroll.getBottom());

            OR

scroll.fullScroll(View.FOCUS_DOWN);

            OR

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

Ou si vous voulez faire défiler doucement et lentement pour pouvoir utiliser ceci:

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();
    }
Maddy
la source
que fait ce catchbloc?
John Sardinha
1
Le bloc Catch consiste à intercepter les exceptions lors du défilement, le cas échéant.
Maddy
5

** pour faire défiler jusqu'à la hauteur désirée. J'ai trouvé une bonne solution **

                scrollView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.scrollBy(0, childView.getHeight());
                    }
                }, 100);
Vikas Chauhan
la source
4

J'ai fait fonctionner cela pour faire défiler vers le bas d'un ScrollView (avec un TextView à l'intérieur):

(Je mets cela sur une méthode qui met à jour le TextView)

final ScrollView myScrollView = (ScrollView) findViewById(R.id.myScroller);
    myScrollView.post(new Runnable() {
    public void run() {
        myScrollView.fullScroll(View.FOCUS_DOWN);
    }
});
Ohiovr
la source
4

Oui, vous pouvez.

Disons que vous en avez un Layoutet que vous en avez plusieurs Views. Donc, si vous souhaitez faire défiler jusqu'à n'importe quel par Viewprogramme, vous devez écrire l'extrait de code suivant:

Par exemple:

content_main.xml

<ScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <Button
            android:id="@+id/btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/txtView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
</ScrollView>

MainActivity.java

ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
Button btn = (Button) findViewById(R.id.ivEventBanner);
TextView txtView = (TextView) findViewById(R.id.ivEditBannerImage);

Si vous voulez faire défiler jusqu'à une vue spécifique View, disons txtview , dans ce cas, écrivez simplement:

scrollView.smoothScrollTo(txtView.getScrollX(),txtView.getScrollY());

Et vous avez terminé.

Pankaj Lilan
la source
3

Remarque: si vous êtes déjà dans un fil, vous devez créer un nouveau fil de discussion, ou il ne fait pas défiler la nouvelle hauteur longue jusqu'à la fin (pour moi). Par exemple:

void LogMe(final String s){
    runOnUiThread(new Runnable() {
        public void run() {
            connectionLog.setText(connectionLog.getText() + "\n" + s);
            final ScrollView sv = (ScrollView)connectLayout.findViewById(R.id.scrollView);
            sv.post(new Runnable() {
                public void run() {
                    sv.fullScroll(sv.FOCUS_DOWN);
                    /*
                    sv.scrollTo(0,sv.getBottom());
                    sv.scrollBy(0,sv.getHeight());*/
                }
            });
        }
    });
}
djdance
la source
3

Ajout d'une autre réponse qui n'implique pas de coordonnées.

Cela amènera la vue souhaitée à se concentrer (mais pas à la position supérieure):

  yourView.getParent().requestChildFocus(yourView,yourView);

public void RequestChildFocus (View child, View focus)

child - L'enfant de ce ViewParent qui veut le focus. Cette vue contiendra la vue focalisée. Ce n'est pas nécessairement le point de vue qui a réellement le centre d'intérêt.

focus - La vue qui est un descendant de l'enfant qui a réellement le focus

Swas_99
la source
Exactement ce dont j'avais besoin, merci. Commencez par demander le focus pour vous faire défiler la vue, puis scrollView.smoothScrollTo (0, scrollView.getChildAt (0) .getBottom ());
Vulovic Vukasin
3

juste le défilement de la page:

ScrollView sv = (ScrollView) findViewById(your_scroll_view);
sv.pageScroll(View.FOCUS_DOWN);
Kirill Vashilo
la source
2

Tout le monde publie des réponses si compliquées.

J'ai trouvé une réponse facile, pour faire défiler vers le bas, bien:

final ScrollView myScroller = (ScrollView) findViewById(R.id.myScrollerView);

// Scroll views can only have 1 child, so get the first child's bottom,
// which should be the full size of the whole content inside the ScrollView
myScroller.smoothScrollTo( 0, myScroller.getChildAt( 0 ).getBottom() );

Et, si nécessaire, vous pouvez mettre la deuxième ligne de code, ci-dessus, dans un exécutable:

myScroller.post( new Runnable() {
    @Override
    public void run() {
        myScroller.smoothScrollTo( 0, myScroller.getChildAt( 0 ).getBottom() );
    }
}

Il m'a fallu beaucoup de recherches et de jeux pour trouver cette solution simple. J'espère que cela vous aide aussi! :)

Nalorin
la source
1

J'utilisais le Runnable avec sv.fullScroll (View.FOCUS_DOWN); Cela fonctionne parfaitement pour le problème immédiat, mais cette méthode permet à ScrollView de prendre le focus sur tout l'écran, si vous faites en sorte que cet AutoScroll se produise à chaque fois, aucun EditText ne pourra recevoir d'informations de l'utilisateur, ma solution était d'utiliser un code différent sous le runnable:

sv.scrollTo (0, sv.getBottom () + sv.getScrollY ());

faire la même chose sans perdre de vue les points de vue importants

salutations.

Sebasu
la source
0

ça marche pour moi

mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mScrollView.post(new Runnable() {
                public void run() {
                    mScrollView.fullScroll(View.FOCUS_DOWN);
                }
            });
        }
    });
Ali Asadi
la source
0
private int totalHeight = 0;

ViewTreeObserver ScrollTr = loutMain.getViewTreeObserver();
ScrollTr.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            loutMain.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        } else {
            loutMain.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
        TotalHeight = loutMain.getMeasuredHeight();

    }
});

scrollMain.smoothScrollTo(0, totalHeight);
P. Patel
la source
0
I had to create Interface

public interface ScrollViewListener {
    void onScrollChanged(ScrollViewExt scrollView, 
                         int x, int y, int oldx, int oldy);
}    

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;

public class CustomScrollView extends ScrollView {
    private ScrollViewListener scrollViewListener = null;
    public ScrollViewExt(Context context) {
        super(context);
    }

    public CustomScrollView (Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public CustomScrollView (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, l, t, oldl, oldt);
        }
    }
}




<"Your Package name ".CustomScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    android:scrollbars="vertical">

    private CustomScrollView scrollView;

scrollView = (CustomScrollView)mView.findViewById(R.id.scrollView);
        scrollView.setScrollViewListener(this);


    @Override
    public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) {
        // We take the last son in the scrollview
        View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1);
        int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));

        // if diff is zero, then the bottom has been reached
        if (diff == 0) {
                // do stuff
            //TODO keshav gers
            pausePlayer();
            videoFullScreenPlayer.setVisibility(View.GONE);

        }
    }
Keshav Gera
la source