-
Notifications
You must be signed in to change notification settings - Fork 11
Description
I noticed multiple issues with the 1.0.0 implementation.
-
If the text contains "...", before the final ellipsis, the custom ellipsis is added in the text, not at the end.
Example :

-
As mentioned in issue Not working 100% #1
availableTextWidth = (availableScreenWidth - paint.measureText(ellipsis)) * maxLinesmaxLines should only apply to the availableScreenWidth and not the ellipsis width. So the line should be :
availableTextWidth = availableScreenWidth * maxLines - paint.measureText(ellipsis)Otherwise, the more line there is, the ellispis will be more distant to the end of last line.
- Anyway, the way
ellipsizedTextis computed withTextUtils.ellipsize(...)works only on single line. With multiple line, when computing.
availableTextWidth = (availableScreenWidth - paint.measureText(ellipsis)) * maxLines
ellipsizedText = TextUtils.ellipsize(text, paint, availableTextWidth, ellipsize)this code doesn't consider that the text is not justified. So every end of line will take spaces, which will be reported on the last line. So the ellipsis can be ellipsed it self by TextView.
Example :

Based on your solution, I wrote this version of EllipsizedTextView which fix previously mentioned issues.
I reused TextUtils.ellipsize() but only on the last line retrieved from the layout, to avoid issue 3.
Also, instead of using overriding onMeasure(), I overridden onLayout()
Note : Only Ellipsize end is handled.
class EllipsizedTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AppCompatTextView(context, attrs, defStyleAttr) {
private var ellipsis = getDefaultEllipsis().toString()
private var ellipsisColor = getDefaultEllipsisColor()
private val ellipsisSpannable: SpannableString
private val spannableStringBuilder = SpannableStringBuilder()
init {
if (ellipsize != TextUtils.TruncateAt.END) {
throw java.lang.IllegalStateException("Only end ellipsize is handled.")
}
if (attrs != null) {
val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.EllipsizedTextView, 0, 0)
ellipsis = typedArray.getString(R.styleable.EllipsizedTextView_ellipsis) ?: getDefaultEllipsis().toString()
ellipsisColor = typedArray.getColor(R.styleable.EllipsizedTextView_ellipsisColor, getDefaultEllipsisColor())
typedArray.recycle()
}
ellipsisSpannable = SpannableString(ellipsis)
ellipsisSpannable.setSpan(ForegroundColorSpan(ellipsisColor), 0, ellipsis.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (changed && layout.lineCount >= maxLines) {
val lastLineNb = maxLines - 1
val ellipsisCount = layout.getEllipsisCount(lastLineNb)
if (ellipsisCount > 0) {
val availableScreenWidth = measuredWidth - compoundPaddingLeft.toFloat() - compoundPaddingRight.toFloat()
val lastLineAvailableTextWidth = availableScreenWidth - paint.measureText(ellipsis)
val lastLineStart = layout.getLineStart(lastLineNb)
val lastLineEnd = layout.getLineEnd(lastLineNb)
val textWithoutLastLine = text.subSequence(0, lastLineStart)
val lastLineText = text.subSequence(lastLineStart, lastLineEnd)
val ellipsizedLasLine = TextUtils.ellipsize(lastLineText, paint, lastLineAvailableTextWidth, ellipsize)
spannableStringBuilder.clear()
val result = spannableStringBuilder.append(textWithoutLastLine).append(ellipsizedLasLine).append(ellipsisSpannable)
text = result
}
}
}
private fun getDefaultEllipsis(): Char {
return Typography.ellipsis
}
private fun getDefaultEllipsisColor(): Int {
return textColors.defaultColor
}
fun isEllipsized(): Boolean {
if (TextUtils.isEmpty(text) || text.length < ellipsis.length) {
return false
}
val finalWord = text.subSequence(text.length - ellipsis.length, text.length)
return TextUtils.equals(finalWord, ellipsis)
}
}
I didn't opened a pull request, since the project is not building with latest Android Studio.
I still share my solution it may help other.