desplazamiento automático de TextView en Android para traer texto a la vista

Tengo un TextView que estoy agregando texto dinámicamente.

en mi archivo main.xml tengo las propiedades establecidas para hacer que mis líneas máximas 19 y barras de desplazamiento sean verticales.

en el archivo .java estoy usando textview.setMovementMethod(new ScrollingMovementMethod()); para permitir el desplazamiento.

El desplazamiento funciona muy bien. Tan pronto como se ocupen 19 líneas y se agreguen más líneas, comenzará a desplazarse como debería. El problema es que quiero que el nuevo texto se desplace a la vista.

Estoy escribiendo el valor de textview.getScrollY() y permanece en 0 sin importar qué (incluso si lo desplazo hacia abajo manualmente y agrego una nueva línea de texto).

en consecuencia textview.scrollTo(0, textview.getScrollY()); no hace nada por mí

¿Hay algún otro método que deba usar para obtener la cantidad de desplazamiento vertical para la vista de textview ? Todo lo que he leído dice que, a todos los efectos, lo que estoy haciendo debería estar funcionando: /

Hizo algunas excavaciones a través de la fuente de TextView, pero esto es lo que se me ocurrió. No es necesario que envuelva TextView en un ScrollView y, hasta donde puedo ver, funciona perfectamente.

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

Por favor, avíseme si encuentra un caso donde esto falla. Agradecería poder corregir cualquier error en mi aplicación;)

Editar: Debo mencionar que también uso

 mTextView.setMovementMethod(new ScrollingMovementMethod()); 

después de instanciar mi TextView.

Usa android:gravity="bottom" en el TextView en tu diseño XML. P.ej

  

No me preguntes por qué funciona.

El único problema con este método es si desea volver a desplazarse hacia atrás en la vista de texto, se sigue “bajando” hacia abajo cada vez que se inserta texto nuevo.

esto es lo que utilizo para desplazarme hasta la parte inferior del texto de mi 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); } }); } 

EDITAR: aquí está el diseño XML

        

Las respuestas anteriores no funcionaron correctamente para mí, sin embargo, esto funciona.

Crea un TextView y haz lo siguiente:

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

Use la siguiente función para agregar texto a la Vista de texto.

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

Espero que esto ayude.

TextView ya tiene desplazamiento automático si configura el texto usando cadenas Spannable o Editable con la posición del cursor establecida en ellas.

Primero, configure el método de desplazamiento:

 mTextView.setMovementMethod(new ScrollingMovementMethod()); 

Luego use lo siguiente para configurar el texto:

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

El setSelection () mueve el cursor a ese índice. Cuando un TextView se configura como SPANNABLE, se desplazará automáticamente para hacer visible el cursor. Tenga en cuenta que esto no dibuja el cursor, simplemente desplaza la ubicación del cursor para estar en la sección visible de TextView.

Además, como TextView.append () actualiza el texto a TextView.BufferType.EDITABLE y Editable implementa Spannable, puede hacer esto:

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

Aquí hay una implementación completa de widgets. Simplemente llame a setText () o append () en este widget. Es ligeramente diferente a la anterior porque se extiende desde EditText que ya obliga a que su texto interno sea Editable.

 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); } } } 
  scrollview=(ScrollView)findViewById(R.id.scrollview1); tb2.setTextSize(30); tb2=(TextView)findViewById(R.id.textView2); scrollview.fullScroll(View.FOCUS_DOWN); 

O use esto en TextView:

  

Usé un pequeño truco … en mi caso …

      

(2017) usando 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) } 

Este archivo de trabajo para mí

 // 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 eg 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 , eg:     

para evitar la creación de ficticio scroolview lo hice

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

Implementación simple … en su diseño XML defina su TextView con estos atributos:

  

https://stackoverflow.com/a/7350267/4411645 no funcionó exactamente para mí

  1. getLayout puede lanzar NPE cuando el texto ha sido cambiado recientemente.
  2. scrollTo se debe cambiar a scrollBy
  3. No tiene en cuenta la posición relativa de la vista de texto o los saltos.

No hace falta decir que es un buen punto de partida. Aquí está mi variación de la implementación, dentro de un textwatcher. Tenemos que restar la parte superior de textView desde la parte inferior cuando se calcula el delta porque getLineTop () también devuelve el valor relativo a la parte superior de 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); } 

Puedes jugar con la demora para mejorar tu ux.