How to use custom ellipsis in Android TextView

混江龙づ霸主 提交于 2019-12-30 04:24:14

问题


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

"Lore ipsum ..."

I need

"Lore ipsum ... [See more]"

in order to give the user a clue that clicking on the view is going to expand the full text.

Is it possible ?

I was thinking about check whether TextView has ellipsis and in such a case add the text "[See more]" and after that set ellipsis just before, but I couldn't find the way to do that.

Maybe if I find the position where the text is cutted, I can disable the ellipsis and make a substring and later add "... [See more]", but again I dont know how to get that position.


回答1:


I've finally managed it in this way (may be 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;
}



回答2:


I think the answer from @jmhostalet will degrade the performance (especially when dealing with lists and lots of TextViews) because the TextView draws the text more than once. I've created a custom TextView that solves this in the onMeasure() and therefore only draws the text once.

I've originally posted my answer here: https://stackoverflow.com/a/52589927/1680301

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




回答3:


@George @jmhostalet i was doing this in my recycler view and it degraded the whole performance. `

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



回答4:


Here's a nice way to do it with a Kotlin extension. Note that we need to wait for the view to layout before we can measure and append 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 actually using it like this myTextView.setEllipsizedSuffix(2, "...See more")


Note: if your text comes from a server and may have new line characters, then you can use this method to determine if the text has ellipsized.

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 is from implementation 'org.apache.commons:commons-lang3:3.4'




回答5:


Here is a solution for Kotlin.

The yourTextView.post{} is necessary because the textview won't be ellipsized until after it is rendered.

  val customSuffix = "... [See more]"
  yourTextView.post {
    if (yourTextView.layout.getEllipsisStart(-1) != -1) {
      val newText = yourTextView.text.removeRange(
          yourTextView.layout.getEllipsisStart(-1) - customSuffix.length, yourTextView.text.length
      )
      yourTextView.text = String.format("%s%s", newText, customSuffix)
    }
  }


来源:https://stackoverflow.com/questions/26054717/how-to-use-custom-ellipsis-in-android-textview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!