デフォルトのTextViewはSpannableを使うとEllipsizeがきかなくなるので、TextViewを継承して以下のような子クラスを作ってあげる。
(android:ellipsize="end"かつandroid:maxLinesを設定していないとき相当)
/**
* SpannableStringを使用していてもEllipsize==Endの挙動をするTextView
*
* 参考 : https://www.programmersought.com/article/20037202696/
*/
class SpannableEllipsizeTextView : androidx.appcompat.widget.AppCompatTextView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
/**
* Note: when spannableString sets the Spannable object to spannableString, use the flag value of Spannable.SPAN_EXCLUSIVE_EXCLUSIVE, otherwise the subsequent concatenated string may not be displayed
*/
override fun onDraw(canvas: Canvas?) {
var lineIndex = 0
while (lineIndex < lineCount) {
val charSequence = text
val bottom = layout.getLineBottom(lineIndex)
if (bottom > measuredHeight) {
// もし、途中で見切れるor完全に隠れる行があったら、その直前の行に…を追加して以降は切る。
val lastCharDown = layout.getLineStart(lineIndex) - 1 // 前の行の最後の文字の文全体でのindex。0始まり。
val spannableStringBuilder = SpannableStringBuilder()
spannableStringBuilder.append(charSequence.subSequence(0, lastCharDown + 1)).append("...")
if (charSequence is Spannable) {
// ...の部分も色などを整える
// 直前の文字に揃える
// XXX この部分は、使用されている可能性があるものに合わせてください。
// 今回はForegroundColorSpanとRelativeSizeSpanが使用されている可能性があると想定しています。
val spanColor = charSequence.getSpans<ForegroundColorSpan>(lastCharDown, lastCharDown + 1)
val spanSize = charSequence.getSpans<RelativeSizeSpan>(lastCharDown, lastCharDown + 1)
if (spanColor.size > 0) {
spannableStringBuilder.setSpan(ForegroundColorSpan(spanColor[0].foregroundColor), // XXX 新しいインスタンスにしないと、元々かかっていた部分がspanがかからなくなってしまうので注意。
lastCharDown,
lastCharDown + 3,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
if (spanSize.size > 0) {
spannableStringBuilder.setSpan(RelativeSizeSpan(spanSize[0].sizeChange),
lastCharDown,
lastCharDown + 3,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
text = spannableStringBuilder
break
}
lineIndex++
}
super.onDraw(canvas)
}
}
参考