Android实现文本折叠效果
16lz
2021-01-26
小需求:默认展示4行,超过4行出现“查看全部”,点击则加载浮层显示完整内容;
实现是参考下面网址代码,但是有一些改动(主要涉及纯引英文的文本下面网址的代码可能有些问题)
https://www.jianshu.com/p/f4f99eb932d4
最终显示代码如下:
import android.content.Contextimport android.graphics.Colorimport android.support.v7.widget.AppCompatTextViewimport android.text.Spannableimport android.text.SpannableStringBuilderimport android.text.TextPaintimport android.text.TextUtilsimport android.text.method.LinkMovementMethodimport android.text.style.ClickableSpanimport android.util.AttributeSetimport android.view.Viewimport android.widget.Toast/** * @date: 2020.02.25 */class FoldTextView : AppCompatTextView { private var isSupportFold = false private var clickCallback: TextClickCallback? = null private var isNeedEllipsis = true constructor(context: Context) : this(context, null) { } constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) {} constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { val ta = context.obtainStyledAttributes(attrs, R.styleable.PayFoldTextView) isSupportFold = ta.getBoolean(R.styleable.FoldTextView_supportFold, false) } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) if (isSupportFold) { //获取当前的行数 val lineCount = lineCount val layout = layout val maxLines = maxLines if (maxLines == 0 || lineCount < maxLines || TextUtils.isEmpty(text)) { return } val totalChars = layout.getLineEnd(maxLines - 1) val lastLineStartIndex = layout.getLineStart(maxLines - 1) if (totalChars >= text.length) { return } val mustShowText = text.subSequence(0, lastLineStartIndex) val tailWidth = paint.measureText(TAIL_TEXT) var lastLineText: CharSequence if (LINE_BREAKER == text[totalChars - 1].toString()) { lastLineText = text.subSequence(lastLineStartIndex, totalChars - 1) } else { lastLineText = text.subSequence(lastLineStartIndex, totalChars) } val maxWidth = measuredWidth.toFloat() val ellipsizeLastLineText = TextUtils.ellipsize( lastLineText, paint, maxWidth - tailWidth, TextUtils.TruncateAt.END ) if (ellipsizeLastLineText.length > 2 && ellipsizeLastLineText != lastLineText) { lastLineText = ellipsizeLastLineText.subSequence(0, ellipsizeLastLineText.length - 1) isNeedEllipsis = true } else { isNeedEllipsis = false } val spannableStringBuilder = SpannableStringBuilder(mustShowText) if (!mustShowText.endsWith("\n")) { spannableStringBuilder.append(LINE_BREAKER) } spannableStringBuilder.append(lastLineText) if (isNeedEllipsis) { spannableStringBuilder.append("...") spannableStringBuilder.append(TAIL_SEPARATOR) } else { spannableStringBuilder.append(TAIL_SEPARATOR_O) } spannableStringBuilder.append(buildClickText()) //重新设置文本 movementMethod = LinkMovementMethod.getInstance() highlightColor = Color.TRANSPARENT //设置点击后的颜色为透明 super.setText(spannableStringBuilder) } } companion object { val LINE_BREAKER = "\n" val TAIL_TEXT = "...查看全部" val TAIL_SEPARATOR = " " val TAIL_SEPARATOR_O = " " val TAIL_TEXT_WITHOUT_ELLIPSIS = "查看全部" } fun setClickCallback(clickCallback: TextClickCallback?) { this.clickCallback = clickCallback } private fun buildClickText(): SpannableStringBuilder { val spannableString = SpannableStringBuilder(TAIL_TEXT_WITHOUT_ELLIPSIS) val clickableSpan = object : ClickableSpan() { override fun onClick(widget: View) { clickCallback?.respondClick() } override fun updateDrawState(ds: TextPaint) { super.updateDrawState(ds) ds.color = resources.getColor(R.color.pay_color_0086f6) ds.isUnderlineText = false } } spannableString.setSpan(clickableSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) return spannableString } fun setSupportFold(isSupport: Boolean = false) { isSupportFold = isSupport maxLines = Integer.MAX_VALUE }}
相关注释:
supportFold:是否需要支持文本折叠。
buildClickText()方法主要是给查看全部添加点击事件以及相关样式。
下面代码是:指定Paint属性的宽度下的文本是否与原始文本相同,不相同则需要显示省略号及查看全部。
if (ellipsizeLastLineText.length > 2 && ellipsizeLastLineText != lastLineText) { lastLineText = ellipsizeLastLineText.subSequence(0, ellipsizeLastLineText.length - 1) isNeedEllipsis = true } else { isNeedEllipsis = false }
ellipsize方法需要的相关参数:
text:原始的文本内容 paint:canvas用到的画笔 avail:画布能提供的宽度 where:枚举类型,就是 省略号显示的位置
/** * Returns the original text if it fits in the specified width * given the properties of the specified Paint, * or, if it does not fit, a truncated * copy with ellipsis character added at the specified edge or center. */public static CharSequence ellipsize(CharSequence text, TextPaint p, float avail, TruncateAt where) { return ellipsize(text, p, avail, where, false, null);}
下面的代码加上"\n"是因为在英文条件下,最后一行的文字可能会显示到倒数第二行,所以强制加上换行符。
val spannableStringBuilder = SpannableStringBuilder(mustShowText) if (!mustShowText.endsWith("\n")) { spannableStringBuilder.append(LINE_BREAKER) }
更多相关文章
- Android高德地图开发(2)——地图显示+自定义控件
- Android(安卓)在App中启动另一个App
- Android下EditText的hint的一种显示效果------FloatLabelLayout
- Android使用ListView构造复杂界面,响应点击事件,通过Intent跳转act
- Android(安卓)-- SpannableString 实现富文本效果用法全解析
- 修改Android默认启动项launcher
- Android课程表显示
- android sdk 编译--如何将源代码加入android.jar,以及make原理
- Android(安卓)Studio使用技巧系列教程(三)