Set Text View ellipsize and add view more at end

This will have ellipsize effect.

set Boolean isCheck= true;

put this in the xml:

<TextView
        android:id="@+id/txt_id"
        android:maxLines="2"
        android:ellipsize="end"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

and the code:

txt_id= (TextView)findViewById(R.id.txt_id);
txt_id.setText("data");
txt_id.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View view) {
                   if (isCheck) {
                      txt_id.setMaxLines(10);
                      isCheck = false;
                   } else {
                      txt_id.setMaxLines(2);
                      isCheck = true;
           }
       }
  }

Simpler than the accepted answer:

public static final int MAX_LINES = 3;
public static final String TWO_SPACES = " "; 

String myReallyLongText = "Bacon ipsum dolor amet porchetta venison ham fatback alcatra tri-tip, turducken strip steak sausage rump burgdoggen pork loin. Spare ribs filet mignon salami, strip steak ball tip shank frankfurter corned beef venison. Pig pork belly pork chop andouille. Porchetta pork belly ground round, filet mignon bresaola chuck swine shoulder leberkas jerky boudin. Landjaeger pork chop corned beef, tri-tip brisket rump pastrami flank."

textView.setText(myReallyLongText);
textView.post(new Runnable() {
                @Override
                public void run() {
                    // Past the maximum number of lines we want to display.
                    if (textView.getLineCount() > MAX_LINES) {
                        int lastCharShown = textView.getLayout().getLineVisibleEnd(MAX_LINES - 1);

                        textView.setMaxLines(MAX_LINES);

                        String moreString = context.getString(R.string.more);
                        String suffix = TWO_SPACES + moreString;
                        
                        // 3 is a "magic number" but it's just basically the length of the ellipsis we're going to insert
                        String actionDisplayText = myReallyLongText.substring(0, lastCharShown - suffix.length() - 3) + "..." + suffix;

                        SpannableString truncatedSpannableString = new SpannableString(actionDisplayText);
                        int startIndex = actionDisplayText.indexOf(moreString);
                        truncatedSpannableString.setSpan(new ForegroundColorSpan(context.getColor(android.R.color.blue)), startIndex, startIndex + moreString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                        textView.setText(truncatedSpannableString);
                    }
                }
            });

If you want the "View More" part of your Text to be clickable (but not the entire TextView), utilize ClickableSpan as outlined here in this StackOverflow for How to set the part of the text view is clickable. I would caution you to be aware of the UX implications of this, as normally you truncate your text because you have a lot of it and you don't have much space, so your font size is already probably small. Having a tiny target for users to click to navigate to the full text might not be the best or most accessible user experience, especially if your users are elderly or have mobility issues that make hitting a small part of the screen difficult. Generally I would suggest making your entire TextView clickable rather than a small portion of it for this reason.

As an alternative, you can do as I did and turn this into a custom view. Here's the class; you can modify as you desire using the ClickableSpan code, but since I have not compiled this project in a long, long time I don't wish to make changes that I then need to verify are safe to publish. I welcome an edit if someone wants to tackle that.

public class TruncatingTextView extends AppCompatTextView {
    private static final String TWO_SPACES = "  ";

    private int truncateAfter = Integer.MAX_VALUE;

    private String suffix;
    private final RelativeSizeSpan truncateTextSpan = new RelativeSizeSpan(0.75f);
    private ForegroundColorSpan viewMoreTextSpan;
    private final String moreString = getContext().getString(R.string.more);

    private final String ellipsis = getContext().getString(R.string.ellipsis);

    public TruncatingTextView(Context context) {
        super(context);
        init();
    }

    public TruncatingTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public TruncatingTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        viewMoreTextSpan = new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.upsell_blue));
    }

    public void setText(CharSequence fullText, @Nullable CharSequence afterTruncation, int truncateAfterLineCount) {
        this.suffix = TWO_SPACES + moreString;

        if (!TextUtils.isEmpty(afterTruncation)) {
            suffix += TWO_SPACES + afterTruncation;
        }

        if (this.truncateAfter != truncateAfterLineCount) {
            this.truncateAfter = truncateAfterLineCount;
            setMaxLines(truncateAfter);
        }

        setText(fullText);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if (getLayout() != null && getLayout().getLineCount() > truncateAfter) {
            int lastCharToShowOfFullTextAfterTruncation = getLayout().getLineVisibleEnd(truncateAfter - 1) - suffix.length() - ellipsis.length();

            int startIndexOfMoreString = lastCharToShowOfFullTextAfterTruncation + TWO_SPACES.length() + 1;

            SpannableString truncatedSpannableString = new SpannableString(getText().subSequence(0, lastCharToShowOfFullTextAfterTruncation) + ellipsis + suffix);
            truncatedSpannableString.setSpan(truncateTextSpan, startIndexOfMoreString, truncatedSpannableString.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            truncatedSpannableString.setSpan(viewMoreTextSpan, startIndexOfMoreString, startIndexOfMoreString + moreString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            setText(truncatedSpannableString);
        }
    }
}

Find my answer

   public static void makeTextViewResizable(final TextView tv, final int maxLine, final String expandText, final boolean viewMore) {

    if (tv.getTag() == null) {
        tv.setTag(tv.getText());
    }
    ViewTreeObserver vto = tv.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @SuppressWarnings("deprecation")
        @Override
        public void onGlobalLayout() {

            ViewTreeObserver obs = tv.getViewTreeObserver();
            obs.removeGlobalOnLayoutListener(this);
            if (maxLine == 0) {
                int lineEndIndex = tv.getLayout().getLineEnd(0);
                String text = tv.getText().subSequence(0, lineEndIndex - expandText.length() + 1) + " " + expandText;
                tv.setText(text);
                tv.setMovementMethod(LinkMovementMethod.getInstance());
                tv.setText(
                        addClickablePartTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, maxLine, expandText,
                                viewMore), TextView.BufferType.SPANNABLE);
            } else if (maxLine > 0 && tv.getLineCount() >= maxLine) {
                int lineEndIndex = tv.getLayout().getLineEnd(maxLine - 1);
                String text = tv.getText().subSequence(0, lineEndIndex - expandText.length() + 1) + " " + expandText;
                tv.setText(text);
                tv.setMovementMethod(LinkMovementMethod.getInstance());
                tv.setText(
                        addClickablePartTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, maxLine, expandText,
                                viewMore), TextView.BufferType.SPANNABLE);
            } else {
                int lineEndIndex = tv.getLayout().getLineEnd(tv.getLayout().getLineCount() - 1);
                String text = tv.getText().subSequence(0, lineEndIndex) + " " + expandText;
                tv.setText(text);
                tv.setMovementMethod(LinkMovementMethod.getInstance());
                tv.setText(
                        addClickablePartTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, lineEndIndex, expandText,
                                viewMore), TextView.BufferType.SPANNABLE);
            }
        }
    });

}

private static SpannableStringBuilder addClickablePartTextViewResizable(final Spanned strSpanned, final TextView tv,
                                                                        final int maxLine, final String spanableText, final boolean viewMore) {
    String str = strSpanned.toString();
    SpannableStringBuilder ssb = new SpannableStringBuilder(strSpanned);

    if (str.contains(spanableText)) {


        ssb.setSpan(new MySpannable(false){
            @Override
            public void onClick(View widget) {
                if (viewMore) {
                    tv.setLayoutParams(tv.getLayoutParams());
                    tv.setText(tv.getTag().toString(), TextView.BufferType.SPANNABLE);
                    tv.invalidate();
                    makeTextViewResizable(tv, -1, "See Less", false);
                } else {
                    tv.setLayoutParams(tv.getLayoutParams());
                    tv.setText(tv.getTag().toString(), TextView.BufferType.SPANNABLE);
                    tv.invalidate();
                    makeTextViewResizable(tv, 3, ".. See More", true);
                }
            }
        }, str.indexOf(spanableText), str.indexOf(spanableText) + spanableText.length(), 0);

    }
    return ssb;

}

Another class:-

import android.graphics.Color;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.view.View;

public class MySpannable extends ClickableSpan {

private boolean isUnderline = true;

/**
 * Constructor
 */
public MySpannable(boolean isUnderline) {
    this.isUnderline = isUnderline;
}

@Override
public void updateDrawState(TextPaint ds) {
    ds.setUnderlineText(isUnderline);
    ds.setColor(Color.parseColor("#1b76d3"));
}

@Override
public void onClick(View widget) {


 }
}

Last step to call it:

DetailTv.setText(discription);
makeTextViewResizable(DetailTv, 3, "See More", true);

This can be achieved during Runtime , all you need to do is check the length of string and add Underlined View More at the end of string like this.

I have used length '20' as an example , you can change according to your requirement.

final TextView result = (TextView) findViewById(R.id.textview);

String text = "I tend to shy away from restaurant chains, but wherever I go, PF Chang&apos;s has solidly good food and, like Starbucks, they&apos;re reliable. We were staying in Boston for a week and after a long day and blah blah blah blah...";

if (text.length()>20) {
    text=text.substring(0,20)+"...";
    result.setText(Html.fromHtml(text+"<font color='red'> <u>View More</u></font>"));       

}