Android - Expandable Textview with Animation

Android - Expandable TextView with Animation

You can check my blog post on ExpandableTexTView:

The idea is, initially the TextView will show a small portion of a long text and when it is clicked, it will show the rest of the text.

So here is the code that how I solved it.

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

And add the following line in your attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ExpandableTextView">
<attr name="trimLength" format="integer"/>
</declare-styleable>
</resources>

Put the following in your 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">

<com.rokonoid.widget.ExpandableTextView
android:id="@+id/lorem_ipsum"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

</LinearLayout>

And test your activity

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

Reference: Android – Expandable TextView

Android Expandable text view with View More Button displaying at center after 3 lines

This is how i have achieved the desired output,

MytextView which i want to expand is: tvDescription
I have a see more button with name: btnSeeMore

To check if the textview has more than 4 lines i had a listener for it as follows,

tvDescription.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if(expandable) {
expandable = false;
if (tvDescription.getLineCount() > 4) {
btnSeeMore.setVisibility(View.VISIBLE);
ObjectAnimator animation = ObjectAnimator.ofInt(tvDescription, "maxLines", 4);
animation.setDuration(0).start();
}
}
}
});

I have kept a boolean value to check if textview is already expanded so that there will not be any hickups while collapsing it.

if textview has more than four lines, boolean flag will be true and the button will be visible so this is the code for expanding and collapsing animation.

btnSeeMore.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {

if (!expand) {
expand = true;
ObjectAnimator animation = ObjectAnimator.ofInt(tvDescription, "maxLines", 40);
animation.setDuration(100).start();
btnSeeMore.setImageDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.ic_collapse));
} else {
expand = false;
ObjectAnimator animation = ObjectAnimator.ofInt(tvDescription, "maxLines", 4);
animation.setDuration(100).start();
btnSeeMore.setImageDrawable(ContextCompat.getDrawable(getActivity(),R.drawable.ic_expand));
}

}
});

Comment below for further information

Custom Expandable TextView

Finally I did it my self, here is the repo

https://github.com/CorradiSebastian/ExpandableTextView

Android: Expand/collapse animation

I see that this question became popular so I post my actual solution. The main advantage is that you don't have to know the expanded height to apply the animation and once the view is expanded, it adapts height if content changes. It works great for me.

public static void expand(final View v) {
int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
v.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
final int targetHeight = v.getMeasuredHeight();

// Older versions of android (pre API 21) cancel animations for views with a height of 0.
v.getLayoutParams().height = 1;
v.setVisibility(View.VISIBLE);
Animation a = new Animation()
{
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targetHeight * interpolatedTime);
v.requestLayout();
}

@Override
public boolean willChangeBounds() {
return true;
}
};

// Expansion speed of 1dp/ms
a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}

public static void collapse(final View v) {
final int initialHeight = v.getMeasuredHeight();

Animation a = new Animation()
{
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if(interpolatedTime == 1){
v.setVisibility(View.GONE);
}else{
v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
v.requestLayout();
}
}

@Override
public boolean willChangeBounds() {
return true;
}
};

// Collapse speed of 1dp/ms
a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}

As mentioned by @Jefferson in the comments, you can obtain a smoother animation by changing the duration (and hence the speed) of the animation. Currently, it has been set at a speed of 1dp/ms

Android - create sliding up animation for textview similar to movie credits

i figured it out ...here is the slide in :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator" >

<translate
android:duration="1000"
android:fromYDelta="100%p"
android:toYDelta="0%" />

</set>

and the slide out:

    <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator" android:fillAfter="true" >

<translate
android:duration="1000"
android:fromYDelta="0%"
android:toYDelta="-100%p" />

</set>

this page was very useful for me so i could know what the p stood for in the fromYDelta

here is the final results: Sample Image

Expandable for text view in kotlin

If you need something like intext suffix "Read More" button. Then, you need to make custom view but if you can compromise on that, then use any of the libraries.

  1. https://github.com/Chen-Sir/ExpandableTextView
  2. https://github.com/Blogcat/Android-ExpandableTextView

If you got the answer you want please accept my answer by giving green check. If I haven't got your question then give me more details in comment section of this answer. Love from India.❤️

TextView animation expand only one line

SOLVED

I changed my expand method adding a listener in which i set the height to wrap_content at the end of the animation:

private void expand(final View v) {
v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

v.getLayoutParams().height = 0;
v.setVisibility(View.VISIBLE);

final int targetHeight = v.getMeasuredHeight();

ValueAnimator mAnimator = slideAnimator(0, targetHeight);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {

}

@Override
public void onAnimationEnd(Animator animation) {
v.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
v.requestLayout();
}

@Override
public void onAnimationCancel(Animator animation) {

}

@Override
public void onAnimationRepeat(Animator animation) {

}
});

mAnimator.start();
}

how to proper animate (expand and collapse) a textview with multiple lines

I found the answer here (Hermann Klecker post)
Android: get height of a view before it´s drawn

private void expandView( final View view ) {

view.setVisibility(View.VISIBLE);

LayoutParams parms = (LayoutParams) view.getLayoutParams();
final int width = this.getWidth() - parms.leftMargin - parms.rightMargin;

view.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

final int targetHeight = view.getMeasuredHeight();

view.getLayoutParams().height = 0;

Animation anim = new Animation() {
@Override
protected void applyTransformation( float interpolatedTime, Transformation trans ) {
view.getLayoutParams().height = (int) (targetHeight * interpolatedTime);
view.requestLayout();
}

@Override
public boolean willChangeBounds() {
return true;
}
};

anim.setDuration( ANIMATION_DURATION );
view.startAnimation( anim );
}


Related Topics



Leave a reply



Submit