自定义换行右下角带标志TextView
2022-09-14 本文已影响0人
azu_test

自定义属性
<declare-styleable name="Details">
<attr name="line_width" format="dimension" />
<attr name="detail_width" format="dimension" />
<attr name="detail_color" format="color" />
<attr name="detail_text" format="string" />
<attr name="detail_image" format="reference|color" />
<attr name="detail_image_size" format="dimension" />
代码实现
package com.azu.test
import android.content.Context
import android.graphics.drawable.Drawable
import android.text.*
import android.text.style.DynamicDrawableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.util.AttributeSet
import java.lang.reflect.Method
/**
* @author zau
* @data 2022/09/13
* */
class DetailsTextView : androidx.appcompat.widget.AppCompatTextView {
private var mLineWidth = 0f
private var mDetailWidth = 0f
private var mDetailColor = 0
private lateinit var mDetailText: String
private lateinit var mDetailImage: Drawable
private var mDetailImageSize = 0f
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.Details)
mLineWidth = typedArray.getDimension(R.styleable.Details_line_width, 0f)
mDetailWidth = typedArray.getDimension(R.styleable.Details_detail_width, 0f)
mDetailColor =
typedArray.getColor(R.styleable.Details_detail_color, getContext().getColor(R.color.black))
mDetailText = typedArray.getString(R.styleable.Details_detail_text).toString()
mDetailImage = typedArray.getDrawable(R.styleable.Details_detail_image)!!
mDetailImageSize = typedArray.getDimension(R.styleable.Details_detail_image_size, 0f)
}
fun setProfileIntro(originText: String?) {
if (originText.isNullOrEmpty()) return
var currentLength: Int = 0
val showText = StringBuffer()
for (i in 1..maxLines) {
val currentLineStr = ellipsize(originText.substring(currentLength, originText.length), mLineWidth, "")
if ((currentLength + currentLineStr.length) == originText.length) {
text = originText
return
}
//已经为最后一行,且内容显示不全,需要重新获取最后一行的内容
if (i == maxLines && (currentLength + currentLineStr.length) < originText.length) {
val lastLineStr = ellipsize(
originText.substring(currentLength, originText.length),
mLineWidth - mDetailWidth,
"\u2026"
)
showText.append(lastLineStr).append("${mDetailText}+")
val span = SpannableString(showText)
span.setSpan(
ForegroundColorSpan(mDetailColor),
currentLength + lastLineStr.length + maxLines - 1,
showText.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
mDetailImage.setBounds(0, 0, mDetailImageSize.toInt(), mDetailImageSize.toInt())
val imageSpan = ImageSpan(mDetailImage, DynamicDrawableSpan.ALIGN_CENTER)
span.setSpan(imageSpan, showText.length - 1, showText.length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
text = span
setOnClickListener {
//fixme 做显示更多的操作
}
} else {
//处理第二行首个字符为特殊字符时会把第一行的最后一个字符移动到第二行的异常问题
showText.append("${currentLineStr}\n")
currentLength += currentLineStr.length
}
}
}
private fun ellipsize(originText: String, width: Float, ellipsis: String): CharSequence {
val cls: Class<*> = TextUtils::class.java
val method: Method =
cls.getMethod(
"ellipsize",
CharSequence::class.java,
TextPaint::class.java,
Float::class.javaPrimitiveType,
TextUtils.TruncateAt::class.java,
Boolean::class.javaPrimitiveType,
TextUtils.EllipsizeCallback::class.java,
TextDirectionHeuristic::class.java,
String::class.java
)
method.isAccessible = true
val firstLineStr = method.invoke(
null, originText, paint,
width,
TextUtils.TruncateAt.END,
false,
null,
TextDirectionHeuristics.FIRSTSTRONG_LTR,
ellipsis
)
return firstLineStr as CharSequence
}
}
布局使用
<com.azu.test.DetailsTextView
android:id="@+id/tv_intro"
android:layout_width="260px"
android:layout_height="wrap_content"
android:layout_marginTop="16px"
android:ellipsize="end"
android:lineHeight="32px"
android:lineSpacingExtra="0px"
android:maxLines="2"
android:textColor="#99FFFFFF"
android:textSize="20px"
app:detail_color="#46A78B"
app:detail_image="@drawable/ic_arrow"
app:detail_image_size="20px"
app:detail_text="详情"
app:detail_width="66px"
app:line_width="260px" />
代码设置显示内容
binding.tvIntro.setProfileIntro("azu")