Android TextView implements folding content beyond a fixed number of lines

In the previous article Android TextView Dynamically Setting the Indentation Distance , a label display is added to the front of the TextView, and the TextView is dynamically indented by the label length.

The small requirement this time is that when the content in the TextView exceeds a fixed number of lines, the content needs to be folded to display... and the word show more is spliced ​​behind it. After clicking, all the folded content is displayed and the word hide is spliced ​​behind it.

Let’s take a look at the final rendering first:
Final effect picture 1
After clicking to expand:
Final effect picture 2
Unlike the LeadingMarginSpan that can be used to set the paragraph indentation distance, this time there is no official API to use, we need to calculate it ourselves.

The general idea of ​​steps:

  1. Get the length s1 of the last spliced ​​word
  2. Get the displayable length s2 of the content: the length under a fixed number of lines - the length s1 of the last spliced ​​words
  3. Under the length of s2, the content is set to display the display length s3 of the display...
  4. If the length of s3 is smaller than the original length of the content, it means that it cannot be displayed under the fixed number of lines, and the content displayed in step 3 needs to be spliced ​​with the last word
  5. If step 4 is not satisfied, it means that it can be displayed under a fixed number of lines, and the original content needs to be spliced ​​with the final words
  6. Finally, if the spliced ​​words need to use different font colors, you can use ForegroundColorSpan

The specific code is implemented as follows:

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
    }
}

Guess you like

Origin blog.csdn.net/yuantian_shenhai/article/details/128038828