Android中如何创建含两个圆角彩色标签的Spannable TextView?
Android 实现多圆角标签UI方案
针对你需要的带圆角、不同背景、文字加粗放大的双标签效果,给你两种可行的实现方式:
方式一:自定义Span实现(单TextView内完成)
这种方式可以在单个TextView中嵌入不同样式的标签,核心是自定义ReplacementSpan来绘制带圆角的背景:
- 自定义圆角背景Span类
class RoundedBackgroundSpan( private val bgColor: Int, private val textColor: Int, private val cornerRadius: Float, private val textSize: Float, // 标签文字大小 private val paddingHorizontal: Int, private val paddingVertical: Int ) : ReplacementSpan() { override fun getSize( paint: Paint, text: CharSequence?, start: Int, end: Int, fm: Paint.FontMetricsInt? ): Int { // 计算文字宽度加上左右内边距 return (paint.measureText(text, start, end) + 2 * paddingHorizontal).toInt() } override fun draw( canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint ) { // 保存画笔状态 paint.save() // 设置背景画笔 paint.color = bgColor // 绘制圆角矩形背景 val rect = RectF( x, top.toFloat() + paddingVertical, x + getSize(paint, text, start, end, null).toFloat(), bottom.toFloat() - paddingVertical ) canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint) // 设置文字画笔 paint.color = textColor paint.textSize = textSize paint.isFakeBoldText = true // 加粗文字 // 绘制文字(居中对齐) val textBaseline = y - (paint.descent() + paint.ascent()) / 2 canvas.drawText(text!!, start, end, x + paddingHorizontal, textBaseline, paint) // 恢复画笔状态 paint.restore() } }
- 在代码中使用SpannableString组装标签和普通文字
val textView = findViewById<TextView>(R.id.tv_label_container) val spannable = SpannableString("标签1 标签2 普通内容") // 第一个标签:红色背景,白色文字 val span1 = RoundedBackgroundSpan( Color.RED, Color.WHITE, 16f, // 圆角半径 resources.getDimension(R.dimen.label_text_size), // 标签文字大小,比如16sp resources.getDimensionPixelOffset(R.dimen.label_padding_horizontal), // 左右内边距,比如8dp resources.getDimensionPixelOffset(R.dimen.label_padding_vertical) // 上下内边距,比如4dp ) spannable.setSpan(span1, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) // 第二个标签:蓝色背景,白色文字 val span2 = RoundedBackgroundSpan( Color.BLUE, Color.WHITE, 16f, resources.getDimension(R.dimen.label_text_size), resources.getDimensionPixelOffset(R.dimen.label_padding_horizontal), resources.getDimensionPixelOffset(R.dimen.label_padding_vertical) ) spannable.setSpan(span2, 4, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) textView.text = spannable
- dimens.xml中定义相关尺寸
<dimen name="label_text_size">16sp</dimen> <dimen name="label_padding_horizontal">8dp</dimen> <dimen name="label_padding_vertical">4dp</dimen>
方式二:FlowLayout + 自定义TextView(更灵活,适合多标签场景)
如果标签数量不固定,这种方式扩展性更好:
- 自定义带圆角的标签TextView布局(label_item.xml)
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/rounded_label_bg" android:textColor="@android:color/white" android:textSize="16sp" android:textStyle="bold" android:paddingHorizontal="8dp" android:paddingVertical="4dp" android:layout_marginEnd="8dp"/>
- 圆角背景drawable(rounded_label_bg.xml),可以通过代码动态修改颜色,或者创建多个不同颜色的drawable
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@color/red"/> <corners android:radius="16dp"/> </shape>
- 在布局中使用FlowLayout(比如用Google的FlexboxLayout)
<com.google.android.flexbox.FlexboxLayout android:id="@+id/flex_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:flexWrap="wrap" app:alignItems="center" android:padding="8dp"/>
- 代码中添加标签
val flexLayout = findViewById<FlexboxLayout>(R.id.flex_layout) // 添加第一个标签 val label1 = LayoutInflater.from(this).inflate(R.layout.label_item, flexLayout, false) as TextView label1.text = "标签1" label1.background.setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN) flexLayout.addView(label1) // 添加第二个标签 val label2 = LayoutInflater.from(this).inflate(R.layout.label_item, flexLayout, false) as TextView label2.text = "标签2" label2.background.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) flexLayout.addView(label2) // 添加普通文字 val normalText = TextView(this) normalText.text = "普通内容" normalText.textSize = 14f flexLayout.addView(normalText)
两种方式都能满足你的需求:
- 方式一适合标签和文字必须在同一个TextView的场景
- 方式二更灵活,方便后续添加/删除标签,也更容易调整样式
内容的提问来源于stack exchange,提问作者Raj Kumar
相关产品推荐
相关产品推荐

