3

I'm trying to set ellipsis to the end of my text(multi-line) if the text is too long.

I already know I can use setMaxLines() and setEllipsize() to achieve the effect. However, since my textview's size is dynamically changeable, I don't know the max number of lines that can be displayed. Instead I have the textview's height (by pixel).

How do I set ellipsis based on the height of the view and the text(includes font properties)? If no direct available resource I can use, what could be the easiest possible approach?

yongsunCN
  • 736
  • 7
  • 18

2 Answers2

2

You can use getLineCount() (but only after a layout pass).

See this answer for more information.

Community
  • 1
  • 1
Buddy
  • 10,874
  • 5
  • 41
  • 58
  • getLineCount() will not work because the textview may grow from small height to large height. if I set max line number when the height is small, getLineCount will always return the old small number when the height grows. So the max line number doesn't get updated. Also, set max line number schedules a layout pass, which is not my desire. Thank you for your answer though. – yongsunCN Aug 12 '15 at 23:32
0

I have implemented that using the concept of this answer.

You can create an extension function like this-

/**
 * Calculate max lines according height
 *
 * @param text- text need to be set
 * @param lineCount- invoked with -1 if view height is enough to show full text,
 *                   otherwise invoked with maxLines
 */
inline fun TextView.calculateMaxLines(text: String, crossinline lineCount: (Int) -> (Unit)) {
    val params: PrecomputedTextCompat.Params = TextViewCompat.getTextMetricsParams(this)
    val ref: WeakReference<TextView>? = WeakReference(this)
    GlobalScope.launch(Dispatchers.Default) {
        val computedText = PrecomputedTextCompat.create(text, params)
        ref?.get()?.apply {
            TextViewCompat.setPrecomputedText(this, computedText)
            GlobalScope.launch(Dispatchers.Main) {
                ref.get()?.let {
                    val bounds = it.getLineBounds(0, null)
                    val heightRequired = bounds * it.lineCount
                    val maxLines = if (heightRequired > height) {
                        height / bounds
                    } else -1
                    lineCount.invoke(maxLines)
                }
            }
        }
    }
}

Then you can call it and set maxLines like this-

textView.calculateMaxLines("Line 1\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8") {
            if (it >= 0) {
                tvUserName.maxLines = it
                tvUserName.ellipsize = TextUtils.TruncateAt.END
            }
        }

Or, for Java you can call it like this-

ExtensionsKt.calculateMaxLines(textView, text, maxLines -> {
            if (maxLines >= 0) {
                textView.setMaxLines(maxLines);
                textView.setEllipsize(TextUtils.TruncateAt.END);
            }
            return null;
        });
Barno
  • 766
  • 7
  • 15