前回の記事Android TextView のインデント距離の動的設定では、TextView の前面にラベル表示が追加され、TextView がラベルの長さによって動的にインデントされます。
今回の小さな要件は、TextView 内のコンテンツが一定の行数を超えた場合、コンテンツを表示するには折りたたむ必要があるということです...そして、「もっと見る」という単語がその後ろにつなぎ合わされます。クリックすると、折りたたまれたすべてのコンテンツが表示されます。が表示され、その後ろに「隠す」という単語が貼り付けられます。
最初に最終的なレンダリングを見てみましょう:
クリックして展開した後:
段落のインデント距離を設定するために使用できる LeadingMarginSpan とは異なり、今回は使用する公式 API がないため、自分で計算する必要があります。
手順の一般的な考え方:
- 最後に結合されたワードの長さ s1 を取得します
- コンテンツの表示可能な長さ s2 を取得します: 一定の行数の下の長さ - 最後に結合された単語の長さ s1
- s2の長さの下に、ディスプレイの表示長s3を表示する内容が設定されています...
- s3の長さがコンテンツの元の長さよりも小さい場合は、一定の行数で表示できないことを意味し、ステップ3で表示されたコンテンツを最後の単語でつなぎ合わせる必要があります
- ステップ4が満たされない場合は、一定の行数で表示できることを意味し、元のコンテンツを最後の単語でつなぎ合わせる必要があります
- 最後に、結合された単語で異なるフォントの色を使用する必要がある場合は、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
}
}