You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中如何创建含两个圆角彩色标签的Spannable TextView?

Android 实现多圆角标签UI方案

针对你需要的带圆角、不同背景、文字加粗放大的双标签效果,给你两种可行的实现方式:

方式一:自定义Span实现(单TextView内完成)

这种方式可以在单个TextView中嵌入不同样式的标签,核心是自定义ReplacementSpan来绘制带圆角的背景:

  1. 自定义圆角背景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()
    }
}
  1. 在代码中使用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
  1. 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(更灵活,适合多标签场景)

如果标签数量不固定,这种方式扩展性更好:

  1. 自定义带圆角的标签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"/>
  1. 圆角背景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>
  1. 在布局中使用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"/>
  1. 代码中添加标签
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:53:25