Android实现文本折叠效果

小需求:默认展示4行,超过4行出现“查看全部”,点击则加载浮层显示完整内容;

实现是参考下面网址代码,但是有一些改动(主要涉及纯引英文的文本下面网址的代码可能有些问题)

https://www.jianshu.com/p/f4f99eb932d4

最终显示代码如下:

import android.content.Context
import android.graphics.Color
import android.support.v7.widget.AppCompatTextView
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.TextUtils
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.util.AttributeSet
import android.view.View
import 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
    }
}
<declare-styleable name="FoldTextView">
    <attr name="supportFold" format="boolean"/>
</declare-styleable>

相关注释:

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)
            }
发布了179 篇原创文章 · 获赞 175 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/zhangying1994/article/details/104718314
今日推荐