Last active
March 9, 2020 22:48
-
-
Save juliooa/45a51cae1307072063f1eba5518b8c10 to your computer and use it in GitHub Desktop.
TextView.setExpandableText
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun TextView.setExpandableText(text: String, maxLines: Int, buttonsOnNewLines: Boolean = false) { | |
var layoutLaid = false | |
var layoutDisposable: Disposable? = null | |
setText(text) | |
post { | |
// If more than max lines are to be used for text, use "more-less" clickable | |
// labels in order to expand and collapse the text | |
if (lineCount > maxLines) { | |
// Temporarily set these values on the TextView. | |
// After layout is laid, we'll be able to compute the number of characters | |
// truncated from the text in order to add the "More" clickable label. | |
ellipsize = TextUtils.TruncateAt.END | |
setMaxLines(maxLines) | |
layoutDisposable = globalLayouts().subscribeLoggingErrors(onNext = { | |
if (isLaidOut && !layoutLaid) { | |
layoutLaid = true | |
layoutDisposable?.dispose() | |
val truncatedCharacters = layout.getEllipsisCount(layout.lineCount - 1) | |
if (truncatedCharacters > 0) { | |
val more = context.getString(R.string.more) | |
val less = context.getString(R.string.less) | |
// Additional characters to cut from text, | |
// initially was 1 (for the space between the ellipsis and the "More" label), | |
// but after testing, 5 gives a more correct visual result | |
val additionalCut = 5 | |
val truncatedText = if (buttonsOnNewLines) { | |
String.format("%s…\n%s", text.substring(0, text.length - truncatedCharacters - more.length - additionalCut), more) | |
} else { | |
String.format("%s… %s", text.substring(0, text.length - truncatedCharacters - more.length - additionalCut), more) | |
} | |
val fullText = if (buttonsOnNewLines) { | |
String.format("%s\n%s", text, less) | |
} else { | |
String.format("%s %s", text, less) | |
} | |
val truncatedSpannable = SpannableStringBuilder(truncatedText) | |
val fullSpannable = SpannableStringBuilder(fullText) | |
truncatedSpannable.setSpan(object : ClickableSpan() { | |
override fun onClick(widget: View) { | |
setText(fullSpannable, TextView.BufferType.SPANNABLE) | |
} | |
}, truncatedText.length - more.length, truncatedText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | |
fullSpannable.setSpan(object : ClickableSpan() { | |
override fun onClick(widget: View) { | |
setText(truncatedSpannable, TextView.BufferType.SPANNABLE) | |
} | |
}, fullText.length - less.length, fullText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | |
// Won't be using the ellipsize and maxLines attributes anymore | |
ellipsize = null | |
setMaxLines(Integer.MAX_VALUE) | |
// Start with the truncated text | |
setText(truncatedSpannable, TextView.BufferType.SPANNABLE) | |
movementMethod = LinkMovementMethod.getInstance() | |
} | |
} | |
}) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Use as
text_description.setExpandableText(bigTextDescription, maxLines = 2, buttonsOnNewLines = true)