auto-scrolling TextView dans android pour mettre du texte en vue

j'ai un TextView que j'ajoute dynamiquement du texte.

dans mon main.xml le fichier que j'ai les propriétés définies pour faire mon max de lignes 19 et les barres de défilement verticale.

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

Le défilement fonctionne très bien. Dès que 19 lignes sont prises, et plus de lignes sont ajoutées, il commence à défiler comme il se doit. Le problème est que je veux que le nouveau texte soit affiché.

je suis en train d'écrire le valeur de textview.getScrollY() et il reste à 0 n'importe quoi (même si je les faire défiler manuellement et ajouter une nouvelle ligne de texte).

donc textview.scrollTo(0, textview.getScrollY()); ne fait rien pour moi.

y a-t-il une autre méthode que je devrais utiliser pour obtenir la valeur de défilement vertical pour le <!--7? Tout ce que j'ai lu indique que, à toutes fins pratiques, ce que je fais devrait fonctionner:/

40
demandé sur JJD 2010-08-18 00:32:57

12 réponses

J'ai creusé un peu dans la source de TextView Mais voici ce que j'ai trouvé. Cela ne vous oblige pas à envelopper le TextView dans un ScrollView et, pour autant que je puisse dire, 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 d'être en mesure de corriger les bugs dans mon app ;)

Edit: je tiens à préciser que j'ai aussi utiliser

mTextView.setMovementMethod(new ScrollingMovementMethod());

après avoir instancié mon TextView.

66
répondu KNfLrPn 2013-05-31 10:45:20

Utiliser android:gravity="bottom" sur le TextView de votre mise en page XML. E. g.

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

Ne me demandez pas pourquoi cela fonctionne.

le seul problème avec cette méthode est que si vous voulez ensuite faire défiler vers le haut le textview, il continue d'être "tiré vers le bas" à chaque fois que le nouveau texte est inséré.

48
répondu Bryce Thomas 2012-10-02 11:17:15

c'est ce que j'utilise pour faire défiler jusqu'au bas de mon texte de 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 le code XML de mise en page

<?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>
26
répondu Someone Somewhere 2011-12-14 18:11:40

les réponses Précédentes ne fonctionnent pas correctement pour moi, cela fonctionne cependant.

Créer un TextView et procédez de la manière suivante:

// ...
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 vous aidera.

20
répondu user1230812 2012-03-05 04:23:47

TextView a déjà l'auto-scrolling si vous définissez le texte en utilisant des chaînes de caractères pouvant être insérées ou éditables avec la position du curseur qui y est définie.

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

mTextView.setMovementMethod(new ScrollingMovementMethod());

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

le setSelection () déplace le curseur vers cet index. Lorsqu'une fenêtre TextView est positionnée sur une fenêtre SPANNABLE, elle défile automatiquement pour rendre le curseur visible. Notez que cela ne dessine pas le curseur, il ne fait que défiler l'emplacement du curseur à être dans la section visible de TextView.

aussi, depuis TextView.ajoute () met à jour le texte de TextView.BufferType.ÉDITABLE et Modifiable implémente Spannable, vous pouvez faire ceci:

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

Voici une implémentation widget complète. Il suffit d'appeler setText() ou append() sur ce widget. Il est légèrement différent de celui ci-dessus parce qu'il s'étend de EditText qui oblige 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);
        }
    }
}
6
répondu tsmigiel 2018-07-05 12:06:53
 scrollview=(ScrollView)findViewById(R.id.scrollview1); 
 tb2.setTextSize(30); 
 tb2=(TextView)findViewById(R.id.textView2);                 
 scrollview.fullScroll(View.FOCUS_DOWN);    

Ou de l'utiliser dans le 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
répondu Amitsharma 2015-02-15 12:33:17

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>
1
répondu Stephan 2014-11-30 21:59:47

mise en œuvre Simple...dans votre mise en page XML définir votre TextView avec ces attributs:

<TextView
    ...
    android:gravity="bottom"
    android:scrollbars="vertical"
/>
1
répondu noelicus 2016-04-18 19:41:37

(2017) à l'aide de 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 works pour moi

1
répondu Almaz 2017-10-14 10:44:40
// 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>
0
répondu Maciek 2013-03-09 12:35:43

pour éviter de créer mannequin scroolview je n'ai

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);
    }                   
});
0
répondu barabek_AND_40_chelovek_Ltd 2013-11-28 00:32:04

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

  1. le getLayout pouvez jeter NPE lorsque le texte est changé récemment.
  2. scrollTo doit être remplacé par scrollBy
  3. il ne tient pas compte de la position relative du textview ou des paddings.

Inutile de dire que c'est un bon point de départ. Voici ma variante de l'implémentation, au sein d'un textwatcher. Nous devons soustraire les textView en haut et en bas lors du calcul du delta, car getLineTop() renvoie également la valeur par rapport à la textView haut.

        @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 retard pour améliorer votre expérience utilisateur.

0
répondu AA_PV 2017-05-23 12:09:59