Faire défiler TextView sur Android


772

J'affiche du texte dans une vue de texte qui semble trop longue pour tenir sur un seul écran. Je dois faire défiler mon TextView. Comment puis je faire ça?

Voici le code:

final TextView tv = new TextView(this);
tv.setBackgroundResource(R.drawable.splash);
tv.setTypeface(face);
tv.setTextSize(18);
tv.setTextColor(R.color.BROWN);
tv.setGravity(Gravity.CENTER_VERTICAL| Gravity.CENTER_HORIZONTAL);
tv.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent e) {
        Random r = new Random();
        int i = r.nextInt(101);
        if (e.getAction() == e.ACTION_DOWN) {
            tv.setText(tips[i]);
            tv.setBackgroundResource(R.drawable.inner);
        }
        return true;
    }
});
setContentView(tv);

Réponses:


1722

Vous n'avez pas besoin d'utiliser ScrollViewréellement un .

Réglez simplement le

android:scrollbars = "vertical"

propriétés de votre TextViewdans le fichier xml de votre mise en page.

Utilisez ensuite:

yourTextView.setMovementMethod(new ScrollingMovementMethod());

dans votre code.

Bingo, ça défile!


96
Mais maxLinesvous oblige sûrement à saisir un nombre arbitraire; ce n'est pas quelque chose qui fonctionnera pour chaque taille d'écran et taille de police? Je trouve plus simple de simplement l'envelopper avec un ScrollView, ce qui signifie que je n'ai pas besoin d'ajouter d'autres attributs ou codes XML (comme définir la méthode de déplacement).
Christopher Orr

12
@Christopher, ScrollView nécessite également 'android: layout_height'.
Regex Rookie

11
@Regex: Eh bien oui. Soit vous laissez le ScrollViewprendre autant d'espace qu'il le faut (par exemple via l' android:fillViewportattribut), soit vous définissez la taille spécifique que vous souhaitez. L'utilisation maxLinesne doit pas être utilisée pour définir des tailles d'éléments d'interface utilisateur, ce n'est donc pas une solution.
Christopher Orr

62
vous n'avez pas besoin de définir maxlines. juste le reste.
Stevanicus

13
Pour clarifier ce que tout le monde dit à propos du défilement "lisse": Si vous utilisez cette méthode, le défilement est en fait "lisse" (en ce sens que vous pouvez faire défiler pixel par pixel), mais ce n'est pas cinétique. Dès que vous retirez votre doigt, il cesse de défiler instantanément - il n'y a pas de scintillement. C'est assez inacceptable pour une interface utilisateur moderne, donc je vais modifier la réponse pour m'assurer que d'autres personnes ne perdent pas de temps sur cette "solution".
Timmmm

310

Voici comment je l'ai fait purement en XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <ScrollView
        android:id="@+id/SCROLLER_ID"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"
        android:fillViewport="true">

        <TextView
            android:id="@+id/TEXT_STATUS_ID"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1.0"/>
    </ScrollView>
</LinearLayout>

REMARQUES:

  1. android:fillViewport="true"combiné avec android:layout_weight="1.0"fera que la vue de texte prendra tout l'espace disponible.

  2. Lors de la définition du Scrollview, NE PAS spécifier android:layout_height="fill_parent"sinon le scrollview ne fonctionne pas! (cela m'a fait perdre une heure tout à l'heure! FFS).

CONSEIL DE PRO:

Pour faire défiler par programme vers le bas après avoir ajouté du texte, utilisez ceci:

mTextStatus = (TextView) findViewById(R.id.TEXT_STATUS_ID);
mScrollView = (ScrollView) findViewById(R.id.SCROLLER_ID);

private void scrollToBottom()
{
    mScrollView.post(new Runnable()
    {
        public void run()
        {
            mScrollView.smoothScrollTo(0, mTextStatus.getBottom());
        }
    });
}

12
Il n'est pas nécessaire d'utiliser mTextView.getBottom(), utilisez simplement la méthode mScrollView.fullScroll(View.FOCUS_DOWN)car elle fait partie de l'API ScrollView. Voir ici et ici pour plus d'informations.
ChuongPham

7
Android prévient que le LinearLayoutou le ScrollViewpeut être inutile dans cet exemple (j'ai supprimé LinearLayoutcomplètement le). Il prévient également que pour le TextView, il doit android:layout_height="wrap_content"correspondre au ScrollView. Ces avertissements peuvent être dus aux 3 années qui se sont écoulées depuis la publication de cette réponse. Quoi qu'il en soit, cette réponse prend en charge le défilement et le défilement en douceur ... + 1
skia.heliou

L'ajout <!--suppress AndroidLintUselessParent -->au-dessus de ScrollViewdans le fichier xml prendra soin de ces avertissements.
Louie Bertoncin

Le "conseil pro" ne fonctionne pas pour moi, dans le niveau d'API Android 9. La vue textuelle reste défilée vers le haut après avoir ajouté du texte.
LarsH

Cette approche est beaucoup mieux en utilisant l'approche de réponse acceptée ne produira pas une expérience utilisateur fluide.
seyedrezafar

120

Tout ce qui est vraiment nécessaire est le setMovementMethod (). Voici un exemple d'utilisation d'un LinearLayout.

Fichier main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView
    android:id="@+id/tv1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:text="@string/hello"
    />
</LinearLayout>

Fichier WordExtractTest.java

public class WordExtractTest extends Activity {

    TextView tv1;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        tv1 = (TextView)findViewById(R.id.tv1);

        loadDoc();
    }

    private void loadDoc() {

        String s = "";

        for(int x=0; x<=100; x++) {
            s += "Line: " + String.valueOf(x) + "\n";
        }

        tv1.setMovementMethod(new ScrollingMovementMethod());

        tv1.setText(s);
    }
}

3
Existe-t-il un moyen de définir cette propriété en XML? Je me demande pourquoi ils laisseraient de côté cette option.
Thalur

Cela fonctionne mais est-il possible de le rafraîchir après le défilement? je veux dire après avoir fait défiler le TextView, je vais changer le texte dessus, mais sa position reste défilée même si elle n'est pas requise. son bcose précédemment j'avais appliqué scroll ...
Nirav Dangi

9
pas de barres de défilement et le défilement est maladroit par rapport à la ScrollViewméthode.
Jeffrey Blattman le

1
Utilisez un StringBuilderau lieu d'un String... ce que vous avez est un peu inutile.
Alex Lockwood

4
cela fonctionne mais le défilement n'est pas fluide. Fonctionne toujours bien merci.
frostymarvelous

46

Faites votre affichage de texte en ajoutant simplement ceci

TextView textview= (TextView) findViewById(R.id.your_textview_id);
textview.setMovementMethod(new ScrollingMovementMethod());

16
Cela ne fait pas de défilement cinétique. Ne l'utilisez pas.
Timmmm

3
@Timmmm comment obtenir le rouleau cinétique?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Vous ne voulez pas de "défilement cinétique" pour un texte qui doit être lu.
L'incroyable

41

Il n'est pas nécessaire de mettre

android:Maxlines="AN_INTEGER"`

Vous pouvez faire votre travail en ajoutant simplement:

android:scrollbars = "vertical"

Et, mettez ce code dans votre classe Java:

textview.setMovementMethod(new ScrollingMovementMethod());

Une solution bien meilleure que celle acceptée, car la taille de la barre de défilement correspond exactement au texte et vous ne perdez pas d'espace.
FractalBob

lorsque j'utilise ScrollView comme parent, cette fois-ci, cela ne fonctionne pas
Prince

27

Vous pouvez soit

  1. entourer l' TextViewunScrollView ; ou
  2. définissez la méthode Movement sur ScrollingMovementMethod.getInstance();.

22

La meilleure façon que j'ai trouvée:

Remplacez TextView par un EditText avec ces attributs supplémentaires:

android:background="@null"
android:editable="false"
android:cursorVisible="false"

Il n'est pas nécessaire d'encapsuler dans un ScrollView.


2
Facilement la réponse la meilleure et la plus appropriée, surtout si l'on considère que EditText est une sous-classe TextView et la question est de savoir comment faire défiler la vue textuelle, pas comment contourner le problème. Je voterais deux fois si je pouvais :)
Justin Buser

4
@JustinBuser Je ne pourrais pas être plus en désaccord. :) C'est purement fortuit que cela fonctionne, et rien ne garantit que ce sera le cas dans les futures versions d'Android. Si vous souhaitez faire défiler, utilisez les outils de défilement fournis par Android. ScrollViewest la bonne façon de procéder.
Madbreaks

1
@Madbreaks Il n'y a rien de "fortuit" à ce sujet, EditText EST un TextView avec quelques méthodes et remplacements ajoutés qui est spécialement conçu pour accueillir du texte de longueur variable. En particulier, EditText remplace la valeur de retour de la fonction TextView getDefaultMovementMethod. L'implémentation par défaut renvoie NULL, EditText fait essentiellement la même chose que toutes ces autres réponses suggèrent. En ce qui concerne l'utilisation des outils fournis par Android, la classe EditText est beaucoup moins susceptible de devenir obsolète que n'importe quelle autre méthode trouvée dans ces réponses.
Justin Buser

4
@JustinBuser Mon problème avec cela est que vous dépendez du comportement par défaut de EditText, c'est ce que je voulais dire pourrait très bien changer sur la route (pas du tout que EditText serait déconseillé). Vous pouvez affirmer cela, mais encore une fois, l'idée est d'utiliser des composants et des fonctionnalités qui conviennent à la tâche à accomplir. ScrollView a été explicitement conçu pour englober le défilement. J'essaie toujours de le faire et je suggère toujours aux autres d'utiliser le bon outil pour le travail. Il existe presque toujours plusieurs approches pour tout problème de programmation donné. Quoi qu'il en soit, merci pour la réponse réfléchie.
Madbreaks

16

Facile. Voici comment je l'ai fait:

  1. Côté XML:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        tools:context="com.mbh.usbcom.MainActivity">
        <TextView
            android:id="@+id/tv_log"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical"
            android:text="Log:" />
    </RelativeLayout>
  2. Côté Java:

    tv_log = (TextView) findViewById(R.id.tv_log);
    tv_log.setMovementMethod(new ScrollingMovementMethod());

Prime:

Pour laisser défiler la vue texte au fur et à mesure que le texte la remplit, vous devez ajouter:

    android:gravity="bottom"

dans le fichier XML TextView. Il défilera automatiquement à mesure que le texte entrera.

Bien sûr, vous devez ajouter le texte à l'aide de la fonction append au lieu de définir le texte:

    tv_log.append("\n" + text);

Je l'ai utilisé à des fins de journal.

J'espère que ça aide ;)


14

Il s'agit de "Comment appliquer ScrollBar à votre TextView", en utilisant uniquement XML.

Tout d'abord, vous devez prendre un contrôle Textview dans le fichier main.xml et y écrire du texte ... comme ceci:

<TextView
    android:id="@+id/TEXT"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:text="@string/long_text"/>

Ensuite, placez le contrôle d'affichage de texte entre les vues de défilement pour afficher la barre de défilement de ce texte:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent">

    <ScrollView
        android:id="@+id/ScrollView01"
        android:layout_height="150px"
        android:layout_width="fill_parent">

        <TextView
            android:id="@+id/TEXT"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:text="@string/long_text"/>

    </ScrollView>
</RelativeLayout>

C'est ça...


6
Pourquoi même écrire ça? Il s'agit d'une version presque identique, quoique moins correcte, d'une réponse publiée plus de 6 mois avant que vous ne la rédigiez.
Justin Buser

11

Cela fournira un texte défilant en douceur avec une barre de défilement.

ScrollView scroller = new ScrollView(this);
TextView tv = new TextView(this);
tv.setText(R.string.my_text);
scroller.addView(tv);

Active l'animation bleue. Meilleure réponse ici OMI.
Griffin W.

11

La "astuce pro" ci-dessus de Someone Somewhere ( rendre TextView défilable sur Android ) fonctionne très bien, cependant, que se passe-t-il si vous ajoutez dynamiquement du texte à ScrollView et souhaitez faire défiler automatiquement vers le bas après une ajout uniquement lorsque l'utilisateur est à le bas du ScrollView? (Peut-être parce que si l'utilisateur a fait défiler vers le haut pour lire quelque chose, vous ne voulez pas réinitialiser automatiquement vers le bas pendant un ajout, ce qui serait ennuyeux.)

Bref, le voici:

if ((mTextStatus.getMeasuredHeight() - mScrollView.getScrollY()) <=
        (mScrollView.getHeight() + mTextStatus.getLineHeight())) {
    scrollToBottom();
}

Le mTextStatus.getLineHeight () fera en sorte que vous ne faites pas défilerToBottom () si l'utilisateur se trouve dans une ligne à partir de la fin de ScrollView.


10

Si vous souhaitez faire défiler le texte dans la vue de texte, vous pouvez suivre les étapes suivantes:

Vous devez d'abord avoir à sous-classer textview.

Et puis utilisez ça.

Voici un exemple de vue de texte sous-classée.

public class AutoScrollableTextView extends TextView {

    public AutoScrollableTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setEllipsize(TruncateAt.MARQUEE);
        setMarqueeRepeatLimit(-1);
        setSingleLine();
        setHorizontallyScrolling(true);
    }

    public AutoScrollableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setEllipsize(TruncateAt.MARQUEE);
        setMarqueeRepeatLimit(-1);
        setSingleLine();
        setHorizontallyScrolling(true);
    }

    public AutoScrollableTextView(Context context) {
        super(context);
        setEllipsize(TruncateAt.MARQUEE);
        setMarqueeRepeatLimit(-1);
        setSingleLine();
        setHorizontallyScrolling(true);
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        if(focused)
            super.onFocusChanged(focused, direction, previouslyFocusedRect);
    }

    @Override
    public void onWindowFocusChanged(boolean focused) {
        if(focused)
            super.onWindowFocusChanged(focused);
    }

    @Override
    public boolean isFocused() {
        return true;
    }
}

Maintenant, vous devez utiliser cela dans le XML de cette manière:

 <com.yourpackagename.AutoScrollableTextView
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:text="This is very very long text to be scrolled"
 />

C'est ça.


7

Ajoutez ce qui suit dans la vue de texte en XML.

android:scrollbars="vertical"

Et enfin, ajoutez

textView.setMovementMethod(new ScrollingMovementMethod());

dans le fichier Java.


1
Cela ne fait pas de défilement cinétique. Ne l'utilise pas.
Timmmm

6

Je n'ai pas trouvé le défilement de TextView pour prendre en charge le geste «fling», où il continue de défiler après un mouvement vers le haut ou vers le bas. J'ai fini par l'implémenter moi-même parce que je ne voulais pas utiliser ScrollView pour diverses raisons, et il ne semblait pas y avoir de MovementMethod qui me permettait à la fois de sélectionner du texte et de cliquer sur des liens.


6
soo ... comment avez-vous ajouté le geste fling?
Lou Morda

6

En kotlin pour faire défiler la vue texte

myTextView.movementMethod= ScrollingMovementMethod()

et aussi ajouter en xml cette propriété

    android:scrollbars = "vertical"

5

Lorsque vous avez terminé avec défilement, ajoutez cette ligne à la dernière ligne de la vue lorsque vous entrez quoi que ce soit dans la vue:

((ScrollView) findViewById(R.id.TableScroller)).fullScroll(View.FOCUS_DOWN);

mec, tablescroller est une vue qui a été identifiée par l'attribut id du XML qui a été traité en .. u il suffit de l'essayer .. cela fonctionnera bien .. ses travaux en moi ..
Rahul Baradia

4

Si vous ne souhaitez pas utiliser la solution EditText, vous aurez peut-être plus de chance avec:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.yourLayout);
    (TextView)findViewById(R.id.yourTextViewId).setMovementMethod(ArrowKeyMovementMethod.getInstance());
}

4

Ajoutez ceci à votre disposition XML:

android:ellipsize="marquee"
android:focusable="false"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="To Make An textView Scrollable Inside The TextView Using Marquee"

Et dans le code, vous devez écrire les lignes suivantes:

textview.setSelected(true);
textView.setMovementMethod(new ScrollingMovementMethod());

2
Cela ne fait pas de défilement cinétique. Ne l'utilise pas.
Timmmm

je ne veux pas ellipsiser le texte de fin. Comment fait-on ça.
Sagar Nayak

@SagarNayak utilise Android: ellipsize = "none"
Francis

2

Le code ci-dessous crée une vue de texte à défilement horizontal automatique:

Lors de l'ajout de TextView à l'utilisation xml

<TextView android:maxLines="1" 
          android:ellipsize="marquee"
          android:scrollHorizontally="true"/>

Définissez les propriétés suivantes de TextView dans onCreate ()

tv.setSelected(true);
tv.setHorizontallyScrolling(true); 


1

Utilisez-le comme ça

<TextView  
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:maxLines = "AN_INTEGER"
    android:scrollbars = "vertical"
/>

0

Dans mon cas, Disposition des contraintes, AS 2.3.

Implémentation du code:

YOUR_TEXTVIEW.setMovementMethod(new ScrollingMovementMethod());

XML:

android:scrollbars="vertical"
android:scrollIndicators="right|end"

0

J'ai lutté avec ça pendant plus d'une semaine et j'ai finalement trouvé comment faire fonctionner ça!

Mon problème était que tout défilait comme un «bloc». Le texte lui-même défilait, mais comme un morceau plutôt que ligne par ligne. Cela n'a évidemment pas fonctionné pour moi, car cela couperait les lignes en bas. Toutes les solutions précédentes n'ont pas fonctionné pour moi, j'ai donc conçu ma propre solution.

Voici de loin la solution la plus simple:

Créez un fichier de classe appelé: 'PerfectScrollableTextView' à l'intérieur d'un package, puis copiez et collez ce code dans:

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.TextView;

public class PerfectScrollableTextView extends TextView {

    public PerfectScrollableTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setVerticalScrollBarEnabled(true);
        setHorizontallyScrolling(false);
    }

    public PerfectScrollableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setVerticalScrollBarEnabled(true);
        setHorizontallyScrolling(false);
    }

    public PerfectScrollableTextView(Context context) {
        super(context);
        setVerticalScrollBarEnabled(true);
        setHorizontallyScrolling(false);
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        if(focused)
            super.onFocusChanged(focused, direction, previouslyFocusedRect);
    }

    @Override
    public void onWindowFocusChanged(boolean focused) {
        if(focused)
            super.onWindowFocusChanged(focused);
    }

    @Override
    public boolean isFocused() {
        return true;
    }
}

Enfin changez votre 'TextView' en XML:

De: <TextView

À: <com.your_app_goes_here.PerfectScrollableTextView


1
100% réponse parfaite. J'ai rencontré le même problème que vous mentionnez dans la description. appliquer de nombreuses solutions mais ne fonctionne pas parfaitement. mais votre solution fonctionne parfaitement dans tous les cas. sauve mon temps mec :) Merci
Daxesh Vekariya

@DaxeshVekariya Heureux que cela ait fonctionné pour vous!
Petro

0

Mettez maxLineset à l' scrollbarsintérieur de TextView en xml.

<TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scrollbars="vertical"
    android:maxLines="5" // any number of max line here.
    />

Puis en code java.

textView.setMovementMethod(new ScrollingMovementMethod());


0

J'ai eu ce problème lorsque j'utilisais TextViewà l'intérieur du ScrollView. Cette solution a fonctionné pour moi.

scrollView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                description.getParent().requestDisallowInterceptTouchEvent(false);

                return false;
            }
        });

        description.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                description.getParent().requestDisallowInterceptTouchEvent(true);

                return false;
            }
        });

0

chaque fois que vous devez utiliser ScrollView en tant que parent , et vous utilisez également la méthode de mouvement de défilement avec TextView.

Et lorsque vous effectuez un portrait pour aménager votre appareil à ce moment, un problème se produit . (comme) toute la page peut défiler, mais la méthode de défilement ne peut pas fonctionner.

si vous devez toujours utiliser ScrollView comme méthode de mouvement parent ou de défilement, vous utilisez également ci-dessous desc.

Si vous n'avez aucun problème, vous utilisez EditText au lieu de TextView

voir ci-dessous :

<EditText
     android:id="@+id/description_text_question"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@null"
     android:editable="false"
     android:cursorVisible="false"
     android:maxLines="6"/>

Ici, le EditText se comporte comme TextView

Et votre problème sera résolu


0

XML - Vous pouvez utiliser android:scrollHorizontally attribut

Si le texte est autorisé à être plus large que la vue (et peut donc être défilé horizontalement).

Peut être une valeur booléenne, telle que "true" ou "false".

Prigramacaly - setHorizontallyScrolling(boolean)


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.