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
    }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容