Android TextView前自定义标签
一、效果图
二、代码实现
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Paint.FontMetricsInt
import android.graphics.drawable.Drawable
import android.text.style.ImageSpan
class CenterImageSpan : ImageSpan {
constructor(context: Context, resourceId: Int) : super(context, resourceId) {
}
constructor(drawable: Drawable) : super(drawable) {
}
override fun getSize(
paint: Paint,
text: CharSequence?,
start: Int,
end: Int,
fm: FontMetricsInt?
): Int {
val d = drawable
val rect = d.bounds
if (fm != null) {
val fmPaint = paint.fontMetricsInt
val fontHeight = fmPaint.bottom - fmPaint.top
val drHeight = rect.bottom - rect.top
val top = drHeight / 2 - fontHeight / 4
val bottom = drHeight / 2 + fontHeight / 4
fm.ascent = -bottom
fm.top = -bottom
fm.bottom = top
fm.descent = top
}
return rect.right
}
override fun draw(
canvas: Canvas,
text: CharSequence?,
start: Int,
end: Int,
x: Float,
top: Int,
y: Int,
bottom: Int,
paint: Paint
) {
val b = drawable
canvas.save()
var transY = 0
transY = (bottom - top - b.bounds.bottom) / 2 + top
canvas.translate(x, transY.toFloat())
b.draw(canvas)
canvas.restore()
}
}
tag标签布局layout_tag_textview
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_tag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tab_background"
android:paddingStart="4dp"
android:paddingTop="2dp"
android:paddingEnd="4dp"
android:paddingBottom="2dp"
android:text="标签"
android:textColor="#ff0000" />
页面布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:text="Hello World!" />
</RelativeLayout>
代码实现
val mTextView = findViewById<TextView>(R.id.tv_text)
val text = "# 这是文案这是文案这是文案这是文案这是文案这是文案这是文案这是文案这是文案这是文案这是文案"
val spanBuilder = SpannableStringBuilder(text)
//生成标签View
val tagView = LayoutInflater.from(this).inflate(R.layout.layout_tag_textview, null)
val tagTextView = tagView.findViewById<TextView>(R.id.tv_tag)
//View转bitmap
tagTextView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
tagTextView.layout(0, 0, tagTextView.measuredWidth, tagTextView.measuredHeight)
tagTextView.buildDrawingCache()
val bitmap = tagTextView.drawingCache
//bitmap转drawable
val drawable = BitmapDrawable(this.resources, bitmap)
drawable.setBounds(0, 0, tagTextView.width, tagTextView.height)
spanBuilder.setSpan(
CenterImageSpan(drawable),
0,
1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
mTextView.text = spanBuilder
三、不同部分点击事件
class ClickableColorSpan(val color: Int, val action: (() -> Unit)?) : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = color
ds.isUnderlineText = false;//是否显示下划线
}
override fun onClick(widget: View) {
action?.invoke()
}
}
val name = "名字名字名字"
val content = "内容内容内容内容内容内容"
val spannableString = SpannableString(" ${name} ${content}")
var index = 0
val drawable = ContextCompat.getDrawable(this, R.drawable.circle_red)
val height = resources?.getDimensionPixelOffset(R.dimen.calces_36px) ?: 0 //图片高
val width = resources?.getDimensionPixelOffset(R.dimen.calces_90px) ?: 0 //图片宽度
drawable?.setBounds(0, 0, width, height)
if (drawable != null) {
spannableString.setSpan(
CenterImageSpan(drawable),
0,
1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
index = 1
}
val spanName = ClickableColorSpan(Color.parseColor("#8CE4FA")) {
Toast.makeText(this@MainActivity, "点击了名字", Toast.LENGTH_LONG).show()
}
spannableString.setSpan(
spanName,
index,
index + name.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
index += name.length + 1
val spanContent = ClickableColorSpan(Color.parseColor("#FACE16")) {
Toast.makeText(this@MainActivity, "点击了内容", Toast.LENGTH_LONG).show()
}
spannableString.setSpan(
spanContent,
index,
spannableString.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
mTvSpan?.text = spannableString
mTvSpan?.movementMethod = LinkMovementMethod.getInstance();