web-dev-qa-db-fra.com

défilement automatique de TextView dans Android pour afficher le texte

J'ai une TextView à laquelle j'ajoute du texte de manière dynamique.

dans mon fichier main.xml, j'ai les propriétés définies pour rendre mes lignes et barres de défilement maximales 19 verticales.

dans le fichier .Java, j'utilise textview.setMovementMethod(new ScrollingMovementMethod()); pour permettre le défilement.

Le défilement fonctionne très bien. Dès que 19 lignes sont occupées et que d'autres lignes sont ajoutées, le défilement commence comme il se doit. Le problème est que je veux que le nouveau texte défile dans l'affichage.

J'écris la valeur pour textview.getScrollY() et il reste à 0 quoi qu'il en soit (même si je le déplace manuellement vers le bas et ajoute une nouvelle ligne de texte).

par conséquent textview.scrollTo(0, textview.getScrollY()); ne fait rien pour moi.

Existe-t-il une autre méthode que je devrais utiliser pour obtenir le montant de défilement vertical pour la variable textview? Tout ce que j'ai lu dit que, à toutes fins utiles, ce que je fais devrait fonctionner: /

42
Kyle

Il m'a fallu fouiller dans la source TextView, mais voici ce que j'ai proposé. Cela ne vous oblige pas à envelopper le TextView dans un ScrollView et, autant que je sache, fonctionne parfaitement.

// function to append a string to a TextView as a new line
// and scroll to the bottom if needed
private void addMessage(String msg) {
    // append the new string
    mTextView.append(msg + "\n");
    // find the amount we need to scroll.  This works by
    // asking the TextView's internal layout for the position
    // of the final line and then subtracting the TextView's height
    final int scrollAmount = mTextView.getLayout().getLineTop(mTextView.getLineCount()) - mTextView.getHeight();
    // if there is no need to scroll, scrollAmount will be <=0
    if (scrollAmount > 0)
        mTextView.scrollTo(0, scrollAmount);
    else
        mTextView.scrollTo(0, 0);
}

S'il vous plaît laissez-moi savoir si vous trouvez un cas où cela échoue. J'apprécierais de pouvoir corriger les bugs dans mon application;)

Edit: je devrais mentionner que j'utilise aussi

mTextView.setMovementMethod(new ScrollingMovementMethod());

après avoir instancié mon TextView.

67
KNfLrPn

Utilisez Android:gravity="bottom" sur le TextView dans votre mise en page XML. Par exemple.

<TextView
    ...
    Android:gravity="bottom"
    ...
/>

Ne me demandez pas pourquoi ça marche. 

Le seul problème avec cette méthode est que si vous voulez faire défiler la vue texte vers le haut, elle continue à être "abaissée" vers le bas à chaque nouvelle insertion de texte.

49
Bryce Thomas

c’est ce que j’utilise pour défiler jusqu’au bas du texte de mon chat ...

public void onCreate(Bundle savedInstanceState)
{
    this.chat_ScrollView = (ScrollView) this.findViewById(R.id.chat_ScrollView);
    this.chat_text_chat = (TextView) this.findViewById(R.id.chat_text_chat);
}


public void addTextToTextView()
{
    String strTemp = "TestlineOne\nTestlineTwo\n";

    //append the new text to the bottom of the TextView
    chat_text_chat.append(strTemp);

    //scroll chat all the way to the bottom of the text
    //HOWEVER, this won't scroll all the way down !!!
    //chat_ScrollView.fullScroll(View.FOCUS_DOWN);

    //INSTEAD, scroll all the way down with:
    chat_ScrollView.post(new Runnable()
    {
        public void run()
        {
            chat_ScrollView.fullScroll(View.FOCUS_DOWN);
        }
    });
}

EDIT: voici la mise en page XML

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

    <!-- center chat display -->
    <ScrollView Android:id="@+id/chat_ScrollView"
        Android:layout_width="fill_parent" 
        Android:layout_height="fill_parent"
        Android:layout_alignParentRight="true"
        Android:layout_alignParentLeft="true">

        <TextView Android:id="@+id/chat_text_chat"
            Android:text="center chat" 
            Android:layout_width="fill_parent" 
            Android:layout_height="fill_parent"
            Android:singleLine="false" />

    </ScrollView>

</RelativeLayout>
27
Someone Somewhere

Les réponses précédentes ne fonctionnaient pas correctement pour moi, cela fonctionne cependant.

Créez un TextView et procédez comme suit:

// ...
mTextView = (TextView)findViewById(R.id.your_text_view);
mTextView.setMovementMethod(new ScrollingMovementMethod());
// ...

Utilisez la fonction suivante pour ajouter du texte à TextView.

private void appendTextAndScroll(String text)
{
    if(mTextView != null){
        mTextView.append(text + "\n");
        final Layout layout = mTextView.getLayout();
        if(layout != null){
            int scrollDelta = layout.getLineBottom(mTextView.getLineCount() - 1) 
                - mTextView.getScrollY() - mTextView.getHeight();
            if(scrollDelta > 0)
                mTextView.scrollBy(0, scrollDelta);
        }
    }
}

J'espère que cela t'aides.

21
user1230812

TextView possède déjà le défilement automatique si vous définissez le texte à l'aide de chaînes Spannable ou Editable avec la position du curseur définie.

Tout d'abord, définissez la méthode de défilement:

mTextView.setMovementMethod(new ScrollingMovementMethod());

Ensuite, utilisez ce qui suit pour définir le texte:

SpannableString spannable = new SpannableString(string);
Selection.setSelection(spannable, spannable.length());
mTextView.setText(spannable, TextView.BufferType.SPANNABLE);

SetSelection () déplace le curseur sur cet index. Lorsqu'un TextView est défini sur SPANNABLE, il défilera automatiquement pour rendre le curseur visible. Notez que cela ne dessine pas le curseur, il fait simplement défiler l'emplacement du curseur pour qu'il soit dans la section visible du TextView.

De plus, puisque TextView.append () met à niveau le texte en TextView.BufferType.EDITABLE et Editable implémente Spannable, vous pouvez le faire:

mTextView.append(string);
Editable editable = mTextView.getEditableText();
Selection.setSelection(editable, editable.length());

Voici une implémentation complète du widget. Appelez simplement setText () ou append () sur ce widget. Il diffère légèrement de ce qui est décrit ci-dessus, car il s’agit de EditText, qui force déjà son texte interne à être modifiable.

import Android.content.Context;
import Android.support.v7.widget.AppCompatEditText;
import Android.text.Editable;
import Android.text.Selection;
import Android.text.Spannable;
import Android.text.method.MovementMethod;
import Android.text.method.ScrollingMovementMethod;
import Android.text.method.Touch;
import Android.util.AttributeSet;
import Android.view.MotionEvent;
import Android.view.accessibility.AccessibilityEvent;
import Android.widget.TextView;

public class AutoScrollTextView extends AppCompatEditText {
    public AutoScrollTextView(Context context) {
        this(context, null);
    }

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

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

    @Override
    protected boolean getDefaultEditable() {
        return false;
    }

    @Override
    protected MovementMethod getDefaultMovementMethod() {
        return new CursorScrollingMovementMethod();
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        super.setText(text, type);
        scrollToEnd();
    }

    @Override
    public void append(CharSequence text, int start, int end) {
        super.append(text, start, end);
        scrollToEnd();
    }

    public void scrollToEnd() {
        Editable editable = getText();
        Selection.setSelection(editable, editable.length());
    }

    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);
        event.setClassName(AutoScrollTextView.class.getName());
    }

    /**
     * Moves cursor when scrolled so it doesn't auto-scroll on configuration changes.
     */
    private class CursorScrollingMovementMethod extends ScrollingMovementMethod {

        @Override
        public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
            widget.moveCursorToVisibleOffset();
            return super.onTouchEvent(widget, buffer, event);
        }
    }
}
7
tsmigiel
 scrollview=(ScrollView)findViewById(R.id.scrollview1); 
 tb2.setTextSize(30); 
 tb2=(TextView)findViewById(R.id.textView2);                 
 scrollview.fullScroll(View.FOCUS_DOWN);    

Ou utilisez ceci dans TextView:

<TextView

Android:id="@+id/tb2"
Android:layout_width="fill_parent"
Android:layout_height="225sp"
Android:gravity="top"
Android:background="@Android:drawable/editbox_background"
Android:scrollbars="vertical"/>
4
Amitsharma

(2017) utilisant Kotlin:

// you need this to enable scrolling:
mTextView.movementMethod = ScrollingMovementMethod()
// to enable horizontal scrolling, that means Word wrapping off:
mTextView.setHorizontallyScrolling(true)
...
mTextView.text = "Some long long very long text content"
mTextView.post {
     val scrollAmount = mTextView.layout.getLineTop(mTextView.lineCount) - mTextView.height
     mTextView.scrollTo(0, scrollAmount)
}

Ce fichier fonctionne pour moi

2
Almaz

J'ai utilisé un petit truc ... dans mon cas ....

<FrameLayout
    Android:layout_width="fill_parent"
    Android:layout_height="fill_parent"
    Android:layout_below="@+id/textView"
    Android:layout_alignParentLeft="true"
    Android:layout_alignParentStart="true"
    Android:layout_above="@+id/imageButton">

    <ScrollView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:id="@+id/scrollView"
        Android:layout_gravity="left|top" >

        <TextView
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:inputType="textMultiLine"
            Android:ems="10"
            Android:text="@string/your_text" />
    </ScrollView>

</FrameLayout>
2
Stephan
// Layout Views
    private TextView mConversationView;
    private ScrollView mConversationViewScroller;

use it either in :

public void onCreate(Bundle savedInstanceState)
{
   //...blabla
   setContentView(R.layout.main); 
   //...blablabla
        mConversationView = (TextView) findViewById(R.id.in);       
        mConversationViewScroller = (ScrollView) findViewById(R.id.scroller);
}

or in "special" method e.g. 

public void initializeChatOrSth(...){
        //...blabla
        mConversationView = (TextView) findViewById(R.id.in);       
        mConversationViewScroller = (ScrollView) findViewById(R.id.scroller);
}

public void addTextToTextView()
{

             //...blablabla some code
                byte[] writeBuf = (byte[]) msg.obj;
          // construct a string from the buffer - i needed this or You can use by"stringing"
                String writeMessage = new String(writeBuf);
                mConversationView.append("\n"+"Me:  " + writeMessage);
                mConversationViewScroller.post(new Runnable()
                {
                    public void run()
                    {
                        mConversationViewScroller.fullScroll(View.FOCUS_DOWN);
                    }
                });
}

this one works fine, also we can maually scroll text to the very top - which is impossible when gravity tag in XML is used.

Of course XML (main) the texview should be nested inside scrollview , e.g:

<ScrollView
        Android:id="@+id/scroller"
        Android:layout_width="match_parent"
        Android:layout_height="280dp"
        Android:fillViewport="true"
        Android:keepScreenOn="true"
        Android:scrollbarStyle="insideInset"
        Android:scrollbars="vertical" >

        <TextView
            Android:id="@+id/in"
            Android:layout_width="fill_parent"
            Android:layout_height="wrap_content"
            Android:keepScreenOn="true"
            Android:scrollbars="vertical" >

        </TextView>
    </ScrollView>
1
Maciek

Une mise en oeuvre simple ... dans votre mise en page XML, définissez votre TextView avec ces attributs:

<TextView
    ...
    Android:gravity="bottom"
    Android:scrollbars="vertical"
/>
1
noelicus

https://stackoverflow.com/a/7350267/4411645 n'a pas fonctionné exactement pour moi

  1. getLayout peut lancer NPE lorsque le texte a été modifié récemment.
  2. scrollTo devrait être changé en scrollBy
  3. Il ne tient pas compte de la position relative de la vue texte ou des marges.

Inutile de dire que c'est un bon point de départ. Voici ma variante de l'implémentation, dans un textwatcher. Nous devons soustraire le top textView du bas lors du calcul du delta car getLineTop () renvoie également la valeur relative au top textView.

        @Override
        public void afterTextChanged(Editable editable) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    Layout layout = textView.getLayout();
                    if (layout != null) {
                        int lineTop = layout.getLineTop(textView.getLineCount());
                        final int scrollAmount = lineTop + textView.getPaddingTop()
                                + textView.getPaddingBottom() - textView.getBottom() + textView.getTop();
                        if (scrollAmount > 0) {
                            textView.scrollBy(0, scrollAmount);
                        } else {
                            textView.scrollTo(0, 0);
                        }
                    }
                }
            }, 1000L);
        }

Vous pouvez jouer avec le délai pour améliorer votre ux.

0
AA_PV

pour éviter de créer factice scrollview je l'ai fait

int top_scr,rec_text_scrollY;
top_scr=(int)rec_text.getTextSize()+rec_text.getHeight();
rec_text_scrollY=rec_text.getLineBounds(rec_text.getLineCount()-1, null)-top_scr;
    //repeat scroll here and in rec_text.post. 
    //If not scroll here text will be "jump up" after new append, and immediately scroll down
    //If not scroll in post, than scroll will not be actually processed
if(rec_text_scrollY>0)rec_text.scrollTo(0, rec_text_scrollY);
rec_text.post(new Runnable(){
    @Override
    public void run() {
        if(rec_text_scrollY>0)rec_text.scrollTo(0, rec_text_scrollY);
    }                   
});