Después de de esta extensa búsqueda de datos hemos podido resolver este dilema que presentan algunos lectores. Te compartimos la solución y deseamos que resulte de gran apoyo.
Solución:
Puede consultar la publicación de mi blog en ExpandableTexTView:
La idea es que, inicialmente, TextView mostrará una pequeña parte de un texto largo y cuando se haga clic en él, mostrará el resto del texto.
Así que aquí está el código de cómo lo resolví.
package com.rokonoid.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
/**
* User: Bazlur Rahman Rokon
* Date: 9/7/13 - 3:33 AM
*/
public class ExpandableTextView extends TextView
private static final int DEFAULT_TRIM_LENGTH = 200;
private static final String ELLIPSIS = ".....";
private CharSequence originalText;
private CharSequence trimmedText;
private BufferType bufferType;
private boolean trim = true;
private int trimLength;
public ExpandableTextView(Context context)
this(context, null);
public ExpandableTextView(Context context, AttributeSet attrs)
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ExpandableTextView);
this.trimLength = typedArray.getInt(R.styleable.ExpandableTextView_trimLength, DEFAULT_TRIM_LENGTH);
typedArray.recycle();
setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
trim = !trim;
setText();
requestFocusFromTouch();
);
private void setText()
super.setText(getDisplayableText(), bufferType);
private CharSequence getDisplayableText()
return trim ? trimmedText : originalText;
@Override
public void setText(CharSequence text, BufferType type)
originalText = text;
trimmedText = getTrimmedText(text);
bufferType = type;
setText();
private CharSequence getTrimmedText(CharSequence text)
if (originalText != null && originalText.length() > trimLength)
return new SpannableStringBuilder(originalText, 0, trimLength + 1).append(ELLIPSIS);
else
return originalText;
public CharSequence getOriginalText()
return originalText;
public void setTrimLength(int trimLength)
this.trimLength = trimLength;
trimmedText = getTrimmedText(originalText);
setText();
public int getTrimLength()
return trimLength;
Y agregue la siguiente línea en su attr.xml
Pon lo siguiente en tu main.xml
Y prueba tu actividad
package com.rokonoid.widget;
import android.app.Activity;
import android.os.Bundle;
public class MyActivity extends Activity
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String yourText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
"Ut volutpat interdum interdum. Nulla laoreet lacus diam, vitae " +
"sodales sapien commodo faucibus. Vestibulum et feugiat enim. Donec " +
"semper mi et euismod tempor. Sed sodales eleifend mi id varius. Nam " +
"et ornare enim, sit amet gravida sapien. Quisque gravida et enim vel " +
"volutpat. Vivamus egestas ut felis a blandit. Vivamus fringilla " +
"dignissim mollis. Maecenas imperdiet interdum hendrerit. Aliquam" +
" dictum hendrerit ultrices. Ut vitae vestibulum dolor. Donec auctor ante" +
" eget libero molestie porta. Nam tempor fringilla ultricies. Nam sem " +
"lectus, feugiat eget ullamcorper vitae, ornare et sem. Fusce dapibus ipsum" +
" sed laoreet suscipit. ";
ExpandableTextView expandableTextView = (ExpandableTextView) findViewById(R.id.lorem_ipsum);
expandableTextView.setText(yourText);
Referencia: Android – TextView expandible
Utilice un ObjectAnimator.
ObjectAnimator animation = ObjectAnimator.ofInt(yourTextView, "maxLines", tv.getLineCount());
animation.setDuration(200).start();
Esto expandirá completamente su TextView en más de 200 milisegundos. Puedes reemplazar tv.getLineCount()
con la cantidad de líneas de texto que desee, volver a contraerlo.
—-Actualizar—-
A continuación, se muestran algunos métodos prácticos que puede utilizar:
private void expandTextView(TextView tv)
ObjectAnimator animation = ObjectAnimator.ofInt(tv, "maxLines", tv.getLineCount());
animation.setDuration(200).start();
private void collapseTextView(TextView tv, int numLines)
ObjectAnimator animation = ObjectAnimator.ofInt(tv, "maxLines", numLines);
animation.setDuration(200).start();
Si está en API 16+, puede usar textView.getMaxLines () para determinar fácilmente si su textView se ha expandido o no.
private void cycleTextViewExpansion(TextView tv)
int collapsedMaxLines = 3;
ObjectAnimator animation = ObjectAnimator.ofInt(tv, "maxLines",
tv.getMaxLines() == collapsedMaxLines? tv.getLineCount() : collapsedMaxLines);
animation.setDuration(200).start();
Notas:
Si no se ha establecido maxLines, o si ha establecido la altura de su textView en píxeles, puede obtener una excepción ArrayIndexOutOfBounds.
Los ejemplos anteriores siempre toman 200 ms, ya sea que se expandan en 3 líneas o 400. Si desea una tasa de expansión constante, puede hacer algo como esto:
int duration = (textView.getLineCount() - collapsedMaxLines) * 10;
Creé una biblioteca de código abierto para esto, porque no estaba satisfecho con las otras soluciones que encontré en Internet. Lo puse en GitHub y cualquiera puede usarlo gratis.
public class ExpandableTextView extends TextView
// copy off TextView.LINES
private static final int MAXMODE_LINES = 1;
private OnExpandListener onExpandListener;
private TimeInterpolator expandInterpolator;
private TimeInterpolator collapseInterpolator;
private final int maxLines;
private long animationDuration;
private boolean animating;
private boolean expanded;
private int originalHeight;
public ExpandableTextView(final Context context)
this(context, null);
public ExpandableTextView(final Context context, final AttributeSet attrs)
this(context, attrs, 0);
public ExpandableTextView(final Context context, final AttributeSet attrs, final int defStyle)
super(context, attrs, defStyle);
// read attributes
final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ExpandableTextView, defStyle, 0);
this.animationDuration = attributes.getInt(R.styleable.ExpandableTextView_animation_duration, BuildConfig.DEFAULT_ANIMATION_DURATION);
attributes.recycle();
// keep the original value of maxLines
this.maxLines = this.getMaxLines();
// create default interpolators
this.expandInterpolator = new AccelerateDecelerateInterpolator();
this.collapseInterpolator = new AccelerateDecelerateInterpolator();
@Override
public int getMaxLines()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
return super.getMaxLines();
try
final Field mMaxMode = TextView.class.getField("mMaxMode");
mMaxMode.setAccessible(true);
final Field mMaximum = TextView.class.getField("mMaximum");
mMaximum.setAccessible(true);
final int mMaxModeValue = (int) mMaxMode.get(this);
final int mMaximumValue = (int) mMaximum.get(this);
return mMaxModeValue == MAXMODE_LINES ? mMaximumValue : -1;
catch (final Exception e)
return -1;
/**
* Toggle the expanded state of this @link ExpandableTextView.
* @return true if toggled, false otherwise.
*/
public boolean toggle()
if (this.expanded)
return this.collapse();
return this.expand();
/**
* Expand this @link ExpandableTextView.
* @return true if expanded, false otherwise.
*/
public boolean expand()
if (!this.expanded && !this.animating && this.maxLines >= 0)
this.animating = true;
// notify listener
if (this.onExpandListener != null)
this.onExpandListener.onExpand(this);
// get original height
this.measure
(
MeasureSpec.makeMeasureSpec(this.getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
);
this.originalHeight = this.getMeasuredHeight();
// set maxLines to MAX Integer
this.setMaxLines(Integer.MAX_VALUE);
// get new height
this.measure
(
MeasureSpec.makeMeasureSpec(this.getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
);
final int fullHeight = this.getMeasuredHeight();
final ValueAnimator valueAnimator = ValueAnimator.ofInt(this.originalHeight, fullHeight);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
@Override
public void onAnimationUpdate(final ValueAnimator animation)
final ViewGroup.LayoutParams layoutParams = ExpandableTextView.this.getLayoutParams();
layoutParams.height = (int) animation.getAnimatedValue();
ExpandableTextView.this.setLayoutParams(layoutParams);
);
valueAnimator.addListener(new AnimatorListenerAdapter()
@Override
public void onAnimationEnd(final Animator animation)
ExpandableTextView.this.expanded = true;
ExpandableTextView.this.animating = false;
);
// set interpolator
valueAnimator.setInterpolator(this.expandInterpolator);
// start the animation
valueAnimator
.setDuration(this.animationDuration)
.start();
return true;
return false;
/**
* Collapse this @link TextView.
* @return true if collapsed, false otherwise.
*/
public boolean collapse()
if (this.expanded && !this.animating && this.maxLines >= 0)
this.animating = true;
// notify listener
if (this.onExpandListener != null)
this.onExpandListener.onCollapse(this);
// get new height
final int fullHeight = this.getMeasuredHeight();
final ValueAnimator valueAnimator = ValueAnimator.ofInt(fullHeight, this.originalHeight);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
@Override
public void onAnimationUpdate(final ValueAnimator animation)
final ViewGroup.LayoutParams layoutParams = ExpandableTextView.this.getLayoutParams();
layoutParams.height = (int) animation.getAnimatedValue();
ExpandableTextView.this.setLayoutParams(layoutParams);
);
valueAnimator.addListener(new AnimatorListenerAdapter()
@Override
public void onAnimationEnd(final Animator animation)
// set maxLines to original value
ExpandableTextView.this.setMaxLines(ExpandableTextView.this.maxLines);
ExpandableTextView.this.expanded = false;
ExpandableTextView.this.animating = false;
);
// set interpolator
valueAnimator.setInterpolator(this.collapseInterpolator);
// start the animation
valueAnimator
.setDuration(this.animationDuration)
.start();
return true;
return false;
/**
* Sets the duration of the expand / collapse animation.
* @param animationDuration duration in milliseconds.
*/
public void setAnimationDuration(final long animationDuration)
this.animationDuration = animationDuration;
/**
* Sets a listener which receives updates about this @link ExpandableTextView.
* @param onExpandListener the listener.
*/
public void setOnExpandListener(final OnExpandListener onExpandListener)
this.onExpandListener = onExpandListener;
/**
* Returns the @link OnExpandListener.
* @return the listener.
*/
public OnExpandListener getOnExpandListener()
return onExpandListener;
/**
* Sets a @link TimeInterpolator for expanding and collapsing.
* @param interpolator the interpolator
*/
public void setInterpolator(final TimeInterpolator interpolator)
this.expandInterpolator = interpolator;
this.collapseInterpolator = interpolator;
/**
* Sets a @link TimeInterpolator for expanding.
* @param expandInterpolator the interpolator
*/
public void setExpandInterpolator(final TimeInterpolator expandInterpolator)
this.expandInterpolator = expandInterpolator;
/**
* Returns the current @link TimeInterpolator for expanding.
* @return the current interpolator, null by default.
*/
public TimeInterpolator getExpandInterpolator()
return this.expandInterpolator;
/**
* Sets a @link TimeInterpolator for collpasing.
* @param collapseInterpolator the interpolator
*/
public void setCollapseInterpolator(final TimeInterpolator collapseInterpolator)
this.collapseInterpolator = collapseInterpolator;
/**
* Returns the current @link TimeInterpolator for collapsing.
* @return the current interpolator, null by default.
*/
public TimeInterpolator getCollapseInterpolator()
return this.collapseInterpolator;
/**
* Is this @link ExpandableTextView expanded or not?
* @return true if expanded, false if collapsed.
*/
public boolean isExpanded()
return this.expanded;
public interface OnExpandListener
void onExpand(ExpandableTextView view);
void onCollapse(ExpandableTextView view);
Usar el ExpandableTextView es muy fácil, es solo un TextView normal con algunas funciones adicionales agregadas. Al definir el atributo android: maxLines, puede establecer el número predeterminado de líneas para el estado contraído de TextView.
En su actividad o fragmento:
final ExpandableTextView expandableTextView = (ExpandableTextView) this.findViewById(R.id.expandableTextView);
final Button buttonToggle = (Button) this.findViewById(R.id.button_toggle);
// set animation duration via code, but preferable in your layout files by using the animation_duration attribute
expandableTextView.setAnimationDuration(1000L);
// set interpolators for both expanding and collapsing animations
expandableTextView.setInterpolator(new OvershootInterpolator());
// or set them separately
expandableTextView.setExpandInterpolator(new OvershootInterpolator());
expandableTextView.setCollapseInterpolator(new OvershootInterpolator());
// toggle the ExpandableTextView
buttonToggle.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(final View v)
expandableTextView.toggle();
buttonToggle.setText(expandableTextView.isExpanded() ? R.string.collapse : R.string.expand);
);
// but, you can also do the checks yourself
buttonToggle.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(final View v)
if (expandableTextView.isExpanded())
expandableTextView.collapse();
buttonToggle.setText(R.string.expand);
else
expandableTextView.expand();
buttonToggle.setText(R.string.collapse);
);
// listen for expand / collapse events
expandableTextView.setOnExpandListener(new ExpandableTextView.OnExpandListener()
@Override
public void onExpand(final ExpandableTextView view)
Log.d(TAG, "ExpandableTextView expanded");
@Override
public void onCollapse(final ExpandableTextView view)
Log.d(TAG, "ExpandableTextView collapsed");
);
Puede agregar fácilmente esta biblioteca como una dependencia de Gradle a su proyecto de Android. Eche un vistazo al proyecto en Github para obtener más instrucciones:
https://github.com/Blogcat/Android-ExpandableTextView
Valoraciones y comentarios
Si guardas alguna vacilación y disposición de acrecentar nuestro reseña te proponemos escribir una nota y con mucho placer lo analizaremos.