Android TextView实现超过固定行数折叠内容

在之前的文章Android TextView 动态设置缩进距离中实现了在TextView前端加入一个标签展示,并将TextView动态缩进标签长度距离。

这次的小需求是,当TextView中的内容超过固定行数时,需要折叠内容显示…并在后面拼接show more字样,点击之后将折叠内容全部展示并在后面拼接hide字样。

先来看一下最终效果图:
最终效果图1
点击展开之后:
最终效果图2
不像可以使用LeadingMarginSpan来设置段落缩进距离,这次就没有官方API可以使用的,我们需要自己去计算。

大致步骤思路:

  1. 获取最后拼接字样的长度s1
  2. 获取内容可展示的长度s2:固定行数下长度 - 最后拼接字样的长度s1
  3. 在s2长度下,内容设置为展示不下显示…的显示长度s3
  4. 如果s3长度小于内容原本长度,说明在固定行数下是展示不下的,需要步骤3中显示…的内容拼接最后字样
  5. 如果步骤4不满足,说明在固定行数下是可以展示下的,则需要原本内容拼接最后字样
  6. 最后如果拼接的字样需要使用不同字体颜色,可以使用ForegroundColorSpan

具体代码实现如下:

class MainActivity2 : AppCompatActivity() {

    private val binding: ActivityMain2Binding by lazy {
        ActivityMain2Binding.inflate(layoutInflater)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportActionBar?.hide()
        setContentView(binding.root)
        //记录折叠情况,默认为折叠
        var collapsed = true
        val text =
            "This is a very long long long long long long long content, and more than 3 lines it will be collapsed, so it must be very long long long, now it is end."
        toggleEllipsize(this, binding.tv, 3, text, "show more", R.color.purple_200)
        binding.tv.setOnClickListener {
            if (collapsed) {
                toggleEllipsize(this, binding.tv, 30, text, " hide", R.color.purple_200)
            } else {
                toggleEllipsize(this, binding.tv, 3, text, " show more", R.color.purple_200)
            }
            collapsed = !collapsed
        }
    }

    /**
     * 设置textView结尾...后面显示的文字和颜色
     * @param context 上下文
     * @param textView textview
     * @param maxLines 最大的行数
     * @param originText 原文本
     * @param endText 结尾文字
     * @param endColorID 结尾文字颜色id
     */
    private fun toggleEllipsize(
        context: Context,
        textView: TextView,
        maxLines: Int,
        originText: String,
        endText: String,
        endColorID: Int
    ) {
        textView.viewTreeObserver.addOnGlobalLayoutListener(object :
            ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                val paddingLeft = textView.paddingLeft
                val paddingRight = textView.paddingRight
                val paint = textView.paint
                //获取最后拼接字样的长度
                val moreText = textView.textSize * endText.length
                //获取内容可展示的长度
                val availableTextWidth = (textView.width - paddingLeft - paddingRight) *
                        maxLines - moreText
                val ellipsizeStr: CharSequence = TextUtils.ellipsize(
                    originText, paint,
                    availableTextWidth, TextUtils.TruncateAt.END
                )
                val temp = if (ellipsizeStr.length < originText.length) {
                    //固定行数下展示不下
                    ellipsizeStr.toString() + endText
                } else {
                    //固定行数下可以展示下
                    originText + endText
                }
                val ssb = SpannableStringBuilder(temp)
                ssb.setSpan(
                    ForegroundColorSpan(ContextCompat.getColor(context, endColorID)),
                    temp.length - endText.length,
                    temp.length,
                    Spannable.SPAN_INCLUSIVE_EXCLUSIVE
                )
                textView.text = ssb
                textView.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        })
        //最后记得要设置maxLines才能触发TextView的重新layout
        textView.maxLines = maxLines
    }
}

猜你喜欢

转载自blog.csdn.net/yuantian_shenhai/article/details/128038828