I am trying to set ellipsize of text view. using the following code. I want to add \"view more\" at the end of truncated string after 3 dots. If this would be possible with
In Kotlin adapter you can write like this to "View More" on TextView
if (News[position].description.length > 150) {
holder.desc.text = Html.fromHtml(News[position].description.substring(0, 150) + "..." + "<font color='blue'> <u>View More</u></font>")
} else {
holder.desc.text = News[position].description
}
holder.desc.setOnClickListener {
if (holder.desc.text.toString().endsWith("View More")) {
holder.desc.text = News[position].description
} else {
if (News[position].description.length > 150) {
holder.desc.text = Html.fromHtml(News[position].description.substring(0, 150) + "..." + "<font color='blue'> <u>View More</u></font>")
} else holder.desc.text = News[position].description
}
}
This solution is a bit easier to implement in code. It doesn't support on-the-fly changes well, but can easily be modified to do so.
public class ExpandableTextView extends TextView {
private final String readMoreText = "...read more";
private final int readMoreColor = Color.parseColor("#4A0281");
private int _maxLines = 4;
private CharSequence originalText;
public ExpandableTextView(Context context) {
super(context);
init(context);
}
public ExpandableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ExpandableTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
ViewTreeObserver vto = getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
ViewTreeObserver obs = getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
truncateText();
}
});
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
if (originalText == null) {
originalText = text;
}
}
@Override
public int getMaxLines() {
return _maxLines;
}
@Override
public void setMaxLines(int maxLines) {
_maxLines = maxLines;
}
public void truncateText() {
int maxLines = _maxLines;
String text = getText().toString();
if (getLineCount() >= maxLines) {
int lineEndIndex = getLayout().getLineEnd(maxLines - 1);
String truncatedText = getText().subSequence(0, lineEndIndex - readMoreText.length() + 1) + readMoreText;
Spannable spannable = new SpannableString(truncatedText);
spannable.setSpan(new ForegroundColorSpan(readMoreColor), truncatedText.length() - readMoreText.length(), truncatedText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(spannable, TextView.BufferType.SPANNABLE);
super.setMaxLines(_maxLines);
}
}
public void expandText() {
setText(originalText);
super.setMaxLines(1000);
}
public void reset() {
originalText = null;
}
}
You can use below code for this;
holder.tvMoreInfo.setText(horizontalList.get(position));
holder.tvMoreInfo.post(new Runnable() {
@Override
public void run() {
int lineCount = holder.tvMoreInfo.getLineCount();
if (lineCount<3)
{
}else
{
makeTextViewResizable(holder.tvMoreInfo, 3, "...More", true);
}
}
});
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() {
String text;
int lineEndIndex;
ViewTreeObserver obs = tv.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
if (maxLine == 0) {
lineEndIndex = tv.getLayout().getLineEnd(0);
text = tv.getText().subSequence(0, lineEndIndex - expandText.length() + 1) + " " + "<font color=\"#F15d36\">" + expandText + "</font>";
} else if (maxLine > 0 && tv.getLineCount() >= maxLine) {
lineEndIndex = tv.getLayout().getLineEnd(maxLine - 1);
text = tv.getText().subSequence(0, lineEndIndex - expandText.length() + 1) + " " + "<font color=\"#F15d36\">" + expandText + "</font>";
} else {
lineEndIndex = tv.getLayout().getLineEnd(tv.getLayout().getLineCount() - 1);
text = tv.getText().subSequence(0, lineEndIndex) + " " + "<font color=\"#F15d36\">" + expandText + "</font>";
}
tv.setText(Html.fromHtml(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) {
tv.setLayoutParams(tv.getLayoutParams());
tv.setText(tv.getTag().toString(), TextView.BufferType.SPANNABLE);
tv.invalidate();
if (viewMore) {
makeTextViewResizable(tv, -1, "...Less", false);
} else {
makeTextViewResizable(tv, 3, "...More", true);
}
}
}, str.indexOf(spanableText), str.indexOf(spanableText) + spanableText.length(), 0);
}
return ssb;
}
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);
Instead of using android:layout_alignParentLeft="true" in first textview use android:layout_toLeftOf="@+id/textView1"
This should take care of the overlapping text
Thanks to Jitender's answer.Improving on it I have done the below implementation based on length of text.This might not be ideal solution if you want View More option exactly after specified number of lines but assuming that there are around 50 characters in single line the solution will work well if you are adjustable with number of lines.Below solution will add View More option if text length is greater than 150 and will ellipsize the text to 150 characters.On clicking on View More it will show complete text with Show Less option and on clicking on Show Less again it will ellipsize the text to 150 characters.No separate view is required.Also it works well with recyclerview item's textview.
if(inputText.length()>150)
{
String text=inputText.substring(0,150)+"...";
final String fulltext=inputText;
final SpannableString ss = new SpannableString(text+"View More");
ClickableSpan span1 = new ClickableSpan() {
@Override
public void onClick(View textView) {
// do some thing
SpannableString ss1 = new SpannableString(fulltext+"Show Less");
ClickableSpan span2 = new ClickableSpan() {
@Override
public void onClick(View textView) {
// do some thing
textView.setText(ss);
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
};
ss1.setSpan(span2, fulltext.length(), ss1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ss1.setSpan(new ForegroundColorSpan(Color.BLUE), fulltext.length(), ss1.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(ss1);
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
};
ss.setSpan(span1, 153, 162, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ss.setSpan(new ForegroundColorSpan(Color.BLUE), 153,162,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(ss);
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
else
{
textView.setText(inputText);
}