How to use custom ellipse in Android TextView

I have a TextView with maxlines = 3 and I would like to use my own ellipse instead

"Lore ipsum ..."

      

I need

"Lore ipsum ... [See more]"

      

to make it clear to the user that the full text will expand when the view is clicked.

Is it possible?

I was thinking about checking if the TextView has an ellipsis, in which case add the text "[See more]" and after that set the ellipsis before, but I couldn't find a way to do it.

Maybe if I find the position at which the text is truncated, I can turn off the ellipsis and create a substring and then add "... [More ...]", but again I don't know how to get that position.

+9


source to share


4 answers


I finally got it over with (maybe not the best one):



private void setLabelAfterEllipsis(TextView textView, int labelId, int maxLines){

    if(textView.getLayout().getEllipsisCount(maxLines-1)==0) {
        return; // Nothing to do
    }

    int start = textView.getLayout().getLineStart(0);
    int end = textView.getLayout().getLineEnd(textView.getLineCount() - 1);
    String displayed = textView.getText().toString().substring(start, end);
    int displayedWidth = getTextWidth(displayed, textView.getTextSize());

    String strLabel = textView.getContext().getResources().getString(labelId);
    String ellipsis = "...";
    String suffix = ellipsis + strLabel;

    int textWidth;
    String newText = displayed;
    textWidth = getTextWidth(newText + suffix, textView.getTextSize());

    while(textWidth>displayedWidth){
        newText = newText.substring(0, newText.length()-1).trim();
        textWidth = getTextWidth(newText + suffix, textView.getTextSize());
    }

    textView.setText(newText + suffix);
}

private int getTextWidth(String text, float textSize){
    Rect bounds = new Rect();
    Paint paint = new Paint();
    paint.setTextSize(textSize);
    paint.getTextBounds(text, 0, text.length(), bounds);

    int width = (int) Math.ceil( bounds.width());
    return width;
}

      

+7


source


I think the answer from @jmhostalet will hurt performance (especially when dealing with lists and many TextViews) because the TextView is drawing text more than once. I created a custom TextView that solves this problem in onMeasure()

and therefore only draws the text once.

I originally posted my answer here: fooobar.com/questions/11993120 / ...



And here is the link to the repo: https://github.com/TheCodeYard/EllipsizedTextView

+1


source


@George @jmhostalet I was doing this from a processor's point of view and it hurt performance in general.

ViewTreeObserver vto = previewContent.getViewTreeObserver();
    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                try {
                    Layout layout = previewContent.getLayout();
                    int index1 = layout.getLineStart(previewContent.getMaxLines());
                    if (index1 > 10 && index1 < ab.getPreviewContent().length()) {
                        String s =
                                previewContent.getText().toString().substring(0, index1 - 10);
                        previewContent
                                .setText(Html.fromHtml(
                                        s + "<font color='#DC5530'>...ΰ€”ΰ€° ΰ€ͺΰ₯ΰ₯‡ΰ€‚</font>"));
                    }
                    return true;
                }catch (Exception e)
                {
                    Crashlytics.logException(e);
                }
                return true;
            }
        });' 

      

0


source


Here's a good way to do it with the Kotlin extension. Note that we need to wait for the view to be laid out before we can measure and add the suffix.

IN TextViewExtensions.kt

fun TextView.setEllipsizedSuffix(maxLines: Int, suffix: String) {
    addOnLayoutChangeListener(object: View.OnLayoutChangeListener {
        override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom:     Int) {

            val allText = text.toString()
            var newText = allText
            val tvWidth = width
            val textSize = textSize

            if(!TextUtil.textHasEllipsized(newText, tvWidth, textSize, maxLines)) return

            while (TextUtil.textHasEllipsized(newText, tvWidth, textSize, maxLines)) {
                newText = newText.substring(0, newText.length - 1).trim()
            }

            //now replace the last few chars with the suffix if we can
            val endIndex = newText.length - suffix.length - 1 //minus 1 just to make sure we have enough room
            if(endIndex > 0) {
                newText = "${newText.substring(0, endIndex).trim()}$suffix"
            }

            text = newText

            removeOnLayoutChangeListener(this)
        }
    })
}

      

IN TextUtil.kt

fun textHasEllipsized(text: String, tvWidth: Int, textSize: Float, maxLines: Int): Boolean {
    val paint = Paint()
    paint.textSize = textSize
    val size = paint.measureText(text).toInt()

    return size > tvWidth * maxLines
}

      


Then in fact using it like this myTextView.setEllipsizedSuffix(2, "...See more")


Note. If your text comes from a server and can contain newlines, you can use this method to determine if the text is elliptical.

fun textHasEllipsized(text: String, tvWidth: Int, textSize: Float, maxLines: Int): Boolean {
    val paint = Paint()
    paint.textSize = textSize
    val size = paint.measureText(text).toInt()
    val newLineChars = StringUtils.countMatches(text, "\n")

    return size > tvWidth * maxLines || newLineChars >= maxLines
}

      

StringUtils

of implementation 'org.apache.commons:commons-lang3:3.4'

0


source







All Articles