Hacer que TextView se pueda desplazar en Android


772

Estoy mostrando texto en una vista de texto que parece ser demasiado larga para caber en una pantalla. Necesito hacer mi TextView desplazable. ¿Cómo puedo hacer eso?

Aquí está el código:

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

Respuestas:


1722

No necesita usar un en ScrollViewrealidad.

Solo configura el

android:scrollbars = "vertical"

propiedades de su TextViewen el archivo xml de su diseño.

Luego use:

yourTextView.setMovementMethod(new ScrollingMovementMethod());

en tu código

Bingo, se desplaza!


96
Pero seguramente maxLinesrequiere que ingrese un número arbitrario; ¿Esto no es algo que funcione para cada tamaño de pantalla y tamaño de fuente? Me parece más simple simplemente envolverlo con un ScrollView, lo que significa que no tengo que agregar ningún atributo o código XML adicional (como configurar el método de movimiento).
Christopher Orr

12
@Christopher, ScrollView requiere 'android: layout_height' también.
Regex Rookie

11
@Regex: Bueno, sí. O deja que ScrollViewocupe todo el espacio que necesita (por ejemplo, a través del android:fillViewportatributo), o establece el tamaño específico que desea. El uso maxLinesno debe usarse para establecer tamaños de elementos de la interfaz de usuario, por lo que no es una solución.
Christopher Orr

62
no necesita definir maxlines. solo el resto
Stevanicus

13
Para aclarar lo que todo el mundo está diciendo acerca de "suavizar" el desplazamiento: Si se utiliza este método de desplazamiento es en realidad "suave" (en la que puede desplazarse píxel por píxel), sin embargo, es que no cinética. Tan pronto como retire su dedo, deja de desplazarse instantáneamente, no hay movimiento. Esto es bastante inaceptable para una IU moderna, así que voy a editar la respuesta para asegurarme de que otras personas no pierdan el tiempo con esta "solución".
Timmmm

310

Así es como lo hice puramente 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>

NOTAS

  1. android:fillViewport="true"combinado con android:layout_weight="1.0"hará que la vista de texto ocupe todo el espacio disponible.

  2. Al definir la vista de desplazamiento, ¡NO especifique lo android:layout_height="fill_parent"contrario, la vista de desplazamiento no funciona! (¡Esto me ha hecho perder una hora ahora mismo! FFS).

CONSEJO PRO:

Para desplazarse programáticamente a la parte inferior después de agregar texto, use esto:

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
No es necesario usarlo mTextView.getBottom(), solo use el método mScrollView.fullScroll(View.FOCUS_DOWN)ya que es parte de la API ScrollView. Vea aquí y aquí para más información.
ChuongPham

77
Android advierte que el LinearLayouto el ScrollViewpueden ser inútiles en este ejemplo (eliminé el LinearLayoutcompletamente). También advierte que para el TextView, debe ser android:layout_height="wrap_content"coincidir con el ScrollView. Estas advertencias pueden deberse a los 3 años que han pasado desde que se publicó esta respuesta. En cualquier caso, esta respuesta admite un desplazamiento y un desplazamiento suaves ... + 1
skia.heliou

Agregar <!--suppress AndroidLintUselessParent -->encima del ScrollViewarchivo xml se encargará de esas advertencias.
Louie Bertoncin

El "consejo profesional" no funciona para mí, en el nivel 9 de la API de Android. La vista de texto se desplaza a la parte superior después de agregar texto.
LarsH

Este enfoque es mucho mejor usando el enfoque de respuesta aceptado no producirá una experiencia de usuario fluida.
seyedrezafar

120

Todo lo que es realmente necesario es setMovementMethod (). Aquí hay un ejemplo usando un LinearLayout.

Archivo 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>

Archivo 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
¿Hay alguna forma de establecer esta propiedad en XML? Me pregunto por qué dejarían de lado esa opción.
Thalur

Funciona, pero ¿hay alguna forma de actualizarlo después de desplazarse? Es decir, después de desplazar TextView, voy a cambiar el texto, pero su posición permanece desplazada incluso si no es necesario. su bcose previamente había aplicado desplazamiento ...
Nirav Dangi

99
no hay barras de desplazamiento, y el desplazamiento es torpe en comparación con el ScrollViewmétodo.
Jeffrey Blattman

1
Use un en StringBuilderlugar de un String... lo que tiene es un poco derrochador.
Alex Lockwood

44
esto funciona pero el desplazamiento no es suave. Aún funciona, aunque gracias.
frostymarvelous


41

No es necesario poner

android:Maxlines="AN_INTEGER"`

Puedes hacer tu trabajo simplemente agregando:

android:scrollbars = "vertical"

Y, ponga este código en su clase Java:

textview.setMovementMethod(new ScrollingMovementMethod());

Una solución mucho mejor que la aceptada, ya que el tamaño de la barra de desplazamiento se ajusta exactamente al texto y no desperdicia espacio.
FractalBob

cuando estoy usando ScrollView como padre, esa vez no funciona
Prince

27

Tu también puedes

  1. rodear el TextViewpor a ScrollView; o
  2. establece el método de movimiento en ScrollingMovementMethod.getInstance();.

22

La mejor manera que encontré:

Reemplace TextView con un EditText con estos atributos adicionales:

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

No hay necesidad de envolver en un ScrollView.


2
Fácilmente la respuesta mejor y más apropiada, especialmente teniendo en cuenta que EditText es una subclase TextView y la pregunta es cómo hacer que la vista de texto se pueda desplazar, no cómo solucionar el problema. Votaría dos veces si pudiera :)
Justin Buser

44
@JustinBuser No podría estar más en desacuerdo. :) Es pura casualidad que esto funcione, y no hay garantía de que lo haga en futuras versiones de Android. Si desea desplazarse, use las herramientas de desplazamiento que proporciona Android. ScrollViewEs el camino correcto a seguir.
Madbreaks

1
@Madbreaks No hay nada "fortuito" al respecto, EditText ES un TextView con algunos métodos agregados y anulaciones que está específicamente diseñado para acomodar texto de longitud variable. En particular, EditText anula el valor de retorno de la función TextView getDefaultMovementMethod. La implementación predeterminada devuelve NULL, EditText básicamente hace lo mismo que sugieren todas estas otras respuestas. En lo que respecta al uso de las herramientas que ofrece Android, es mucho menos probable que la clase EditText quede obsoleta que cualquiera de los otros métodos encontrados en estas respuestas.
Justin Buser

44
@JustinBuser Mi problema con eso es que depende del comportamiento predeterminado de EditText, eso es lo que quise decir que podría cambiar en el futuro (en absoluto, EditText sería obsoleto). Puede argumentar que, pero de nuevo, la idea es usar componentes y características que sean apropiados para la tarea en cuestión. ScrollView fue diseñado explícitamente para abarcar el desplazamiento. Siempre trato de, y siempre sugiero que otros usen la herramienta adecuada para el trabajo. Casi siempre hay múltiples enfoques para cualquier problema de programación dado. De todos modos, gracias por la atenta respuesta.
Madbreaks

16

Simple. Así es como lo hice:

  1. Lado 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. Lado de Java:

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

Prima:

Para permitir que la vista de texto se desplace hacia abajo a medida que el texto lo llena, debe agregar:

    android:gravity="bottom"

al archivo XML TextView. Se desplazará hacia abajo automáticamente a medida que ingrese más texto.

Por supuesto, debe agregar el texto utilizando la función de agregar en lugar de establecer el texto:

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

Lo usé para fines de registro.

Espero que esto ayude ;)


14

Esto es "Cómo aplicar ScrollBar a su TextView", utilizando solo XML.

Primero, debe tomar un control Textview en el archivo main.xml y escribir algo de texto en él ... de esta manera:

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

Luego, coloque el control de vista de texto entre la vista de desplazamiento para mostrar la barra de desplazamiento para este texto:

<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>

Eso es...


66
¿Por qué incluso escribir esto? Esta es una versión casi idéntica, aunque menos correcta, de una respuesta que se publicó más de 6 meses antes de que la escribiera.
Justin Buser

11

Esto proporcionará un texto de desplazamiento suave con una barra de desplazamiento.

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

Habilita la animación azul. La mejor respuesta aquí OMI.
Griffin

11

Sin embargo, el "consejo profesional" anterior de Someone Somewhere ( Hacer que TextView se pueda desplazar en Android ) funciona de maravilla, ¿qué sucede si agrega texto dinámicamente a ScrollView y desea desplazarse automáticamente hacia la parte inferior después de un agregado solo cuando el usuario está en la parte inferior de ScrollView? (Quizás porque si el usuario se ha desplazado hacia arriba para leer algo que no desea restablecer automáticamente en la parte inferior durante un apéndice, lo que sería molesto).

De todos modos, aquí está:

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

El mTextStatus.getLineHeight () lo hará para que no se desplace a ToBottom () si el usuario está dentro de una línea desde el final de ScrollView.


10

Si desea que el texto se desplace dentro de la vista de texto, puede seguir lo siguiente:

Primero deberías subclasificar textview.

Y luego usa eso.

El siguiente es un ejemplo de una vista de texto subclasificada.

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

Ahora, tienes que usar eso en el XML de esta manera:

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

Eso es.


7

Agregue lo siguiente en la vista de texto en XML.

android:scrollbars="vertical"

Y finalmente, agregue

textView.setMovementMethod(new ScrollingMovementMethod());

en el archivo Java


1
Esto no hace desplazamiento cinético. No lo uses.
Timmmm

6

No encontré el desplazamiento de TextView para admitir el gesto de 'lanzamiento', donde continúa desplazándose después de un movimiento hacia arriba o hacia abajo. Terminé implementando eso yo mismo porque no quería usar un ScrollView por varias razones, y no parecía haber un MoveMethod que me permitiera seleccionar texto y hacer clic en los enlaces.


66
entonces ... ¿cómo agregaste el gesto de lanzamiento?
Lou Morda

6

En kotlin por hacer que la vista de texto se pueda desplazar

myTextView.movementMethod= ScrollingMovementMethod()

y también agregue en xml esta propiedad

    android:scrollbars = "vertical"

5

Cuando haya terminado con el desplazamiento, agregue esta línea a la última línea de la vista cuando ingrese algo en la vista:

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

tio, tablescroller es una vista que fue identificado por el atributo id del XML que se procesa en .. u .. Haga la prueba que funciona bien .. ll sus obras me fr ..
Rahul Baradia

4

Si no desea utilizar la solución EditText, entonces podría tener mejor suerte con:

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

4

Agregue esto a su diseño 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"

Y en el código tienes que escribir las siguientes líneas:

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

2
Esto no hace desplazamiento cinético. No lo uses.
Timmmm

No quiero elipsar el texto final. cómo lo hago.
Sagar Nayak

@SagarNayak usa android: ellipsize = "none"
Francis

2

El siguiente código crea una vista de texto de desplazamiento horizontal automático:

Al agregar TextView al uso xml

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

Establezca las siguientes propiedades de TextView en onCreate ()

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


1

Úselo así

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

0

En mi caso, diseño de restricción AS 2.3.

Implementación de código:

YOUR_TEXTVIEW.setMovementMethod(new ScrollingMovementMethod());

XML:

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

0

¡Luché con esto durante más de una semana y finalmente descubrí cómo hacer que esto funcione!

Mi problema era que todo se desplazaría como un "bloque". El texto en sí se desplazaba, pero como un fragmento en lugar de línea por línea. Obviamente, esto no funcionó para mí, porque cortaría las líneas en la parte inferior. Todas las soluciones anteriores no me funcionaron, así que diseñé la mía.

Aquí está la solución más fácil con diferencia:

Cree un archivo de clase llamado: 'PerfectScrollableTextView' dentro de un paquete, luego copie y pegue este código en:

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

Finalmente cambie su 'TextView' en XML:

Desde: <TextView

A: <com.your_app_goes_here.PerfectScrollableTextView


1
100% de respuesta perfecta. Me enfrenté al mismo problema que mencionas en la descripción. aplica muchas soluciones pero no funciona perfectamente. pero su solución funciona perfectamente en todos los casos. save my time man :) Gracias
Daxesh Vekariya

@DaxeshVekariya Me alegro de que te haya funcionado.
Petro

0

Poner maxLines y scrollbarsdentro 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.
    />

Luego en código java.

textView.setMovementMethod(new ScrollingMovementMethod());


0

Tuve este problema cuando estaba usando TextViewdentro de ScrollView. Esta solución me ha funcionado.

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

siempre que necesite usar ScrollView como padre , y también use el método de movimiento de desplazamiento con TextView.

Y cuando haces retratos para apaisar tu dispositivo, ese momento ocurre algún problema . (como) toda la página es desplazable pero el método de movimiento de desplazamiento no puede funcionar.

si todavía necesita usar ScrollView como método principal o de movimiento de desplazamiento, entonces también use la siguiente descripción.

Si no tiene ningún problema, use EditText en lugar de TextView

vea abajo :

<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"/>

Aquí, EditText se comporta como TextView

Y tu problema será resuelto


0

XML: puede usar android:scrollHorizontallyAttribute

Si se permite que el texto sea más ancho que la vista (y, por lo tanto, se puede desplazar horizontalmente).

Puede ser un valor booleano, como "verdadero" o "falso".

Prigramacaly - setHorizontallyScrolling(boolean)


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.