Android基础–自定义SeekBar

Android 中的 SeekBar(拖动条)是 ProgressBar 的可交互版本,用户可以通过拖动 thumb(滑块/拇指)来调节进度值。系统自带的 SeekBar 样式比较单一,在实际产品中几乎都需要自定义(颜色、圆角、渐变、thumb 形状、进度文字、禁用状态等)。

下面从 2025–2026 年实际开发角度,给你一套最实用的自定义 SeekBar 方案,按复杂度递增排列。

1. 最常用方式:通过 XML + layer-list / clip drawable 自定义(推荐 80% 场景)

优点:无需写 Java/Kotlin 代码,兼容性好,性能最高
缺点:不能动态改变 thumb 内容(如文字、图片随进度变)

步骤

  1. res/drawable/seekbar_bg.xml (背景轨道 – 灰色底)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#E0E0E0" />           <!-- 未激活部分颜色 -->
    <corners android:radius="8dp" />             <!-- 圆角 -->
    <size android:height="8dp" />                <!-- 轨道高度 -->
</shape>
  1. res/drawable/seekbar_progress.xml (已走过的进度 – 渐变/纯色)
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape android:shape="rectangle">
            <solid android:color="#E0E0E0" />
            <corners android:radius="8dp" />
            <size android:height="8dp" />
        </shape>
    </item>

    <item android:id="@android:id/progress">
        <clip>
            <shape android:shape="rectangle">
                <gradient
                    android:startColor="#FF4081"
                    android:endColor="#3F51B5"
                    android:angle="0" />               <!-- 渐变色 -->
                <corners android:radius="8dp" />
                <size android:height="8dp" />
            </shape>
        </clip>
    </item>
</layer-list>
  1. res/drawable/seekbar_thumb.xml (滑块)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="oval">
            <solid android:color="#FF4081" />
            <size android:width="28dp" android:height="28dp" />
            <stroke android:width="4dp" android:color="#33FF4081" /> <!-- 按下光环 -->
        </shape>
    </item>
    <item>
        <shape android:shape="oval">
            <solid android:color="#FF4081" />
            <size android:width="24dp" android:height="24dp" />
            <stroke android:width="3dp" android:color="#FFFFFF" />
        </shape>
    </item>
</selector>
  1. 布局中使用
<SeekBar
    android:id="@+id/custom_seekbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:max="100"
    android:progress="30"
    android:progressDrawable="@drawable/seekbar_progress"
    android:thumb="@drawable/seekbar_thumb"
    android:thumbOffset="0dp"               <!-- 重要:让 thumb 居中对齐轨道 -->
    android:minHeight="30dp"                <!-- 增大触摸热区 -->
    android:maxHeight="30dp" />

小技巧

  • android:thumbOffset="0dp" → 让 thumb 中心对齐轨道中心(默认有偏移)
  • 想让轨道更粗 → 同时设置 minHeightmaxHeight 相同值
  • 想禁用时变灰 → 用 android:enabled="false" + selector 区分状态

2. 进阶:Thumb 上显示当前进度文字(最常见需求)

方案一:自定义 SeekBar 类 + 在 onDraw 画文字(推荐)

class TextOnThumbSeekBar @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : androidx.appcompat.widget.AppCompatSeekBar(context, attrs, defStyleAttr) {

    private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.WHITE
        textSize = 14f.spToPx(context)
        textAlign = Paint.Align.CENTER
    }

    private val bgPaint = Paint().apply {
        color = Color.parseColor("#33000000")
        style = Paint.Style.FILL
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        // 计算 thumb 中心位置
        val thumb = thumb ?: return
        val thumbBounds = thumb.bounds
        val thumbX = (thumbBounds.left + thumbBounds.right) / 2f + paddingLeft
        val thumbY = height / 2f

        val progressText = progress.toString()

        // 画圆形背景(可选)
        canvas.drawCircle(thumbX, thumbY, 20f, bgPaint)

        // 画文字
        canvas.drawText(progressText, thumbX, thumbY - (textPaint.fontMetrics.ascent + textPaint.fontMetrics.descent) / 2, textPaint)
    }
}
<!-- 布局中使用自定义类 -->
<你的包名.TextOnThumbSeekBar
    android:id="@+id/seekbar_with_text"
    ... />

方案二:用 View作为 thumb(更灵活,但性能稍差)

fun getThumb(progress: Int): Drawable {
    val tv = TextView(context).apply {
        text = progress.toString()
        setTextColor(Color.WHITE)
        setBackgroundResource(R.drawable.round_bg_purple)
        gravity = Gravity.CENTER
        setPadding(12.dp, 6.dp, 12.dp, 6.dp)
        measure(0, 0)
        layout(0, 0, measuredWidth, measuredHeight)
    }
    return BitmapDrawable(resources, tv.drawToBitmap())
}

// 在代码中设置
seekBar.thumb = getThumb(seekBar.progress)

3. 更高级玩法(2025–2026 常见需求)

需求实现方式简述推荐优先级
渐变进度条layer-list + gradient★★★★★
Thumb 带阴影/发光shape + elevation / layer-list 多层★★★★☆
垂直 SeekBar自定义 View 或 rotation 270°(注意触摸)★★★☆☆
离散点(步进)android:thumbTint + setKeyProgressIncrement()★★★★☆
带刻度 + 文字指示继承 SeekBar + onDraw 画刻度线★★★★☆
视频进度条(缩略图)自定义 thumb + BitmapDrawable 动态更新★★★☆☆
禁用/只读状态美化selector + state_enabled★★★★★
触摸热区更大minHeight/maxHeight 设大值★★★★★

4. 快速 Checklist(生产常用属性)

android:progressTint="#FF4081"           <!-- API21+ 进度颜色 -->
android:thumbTint="#FF4081"              <!-- 拇指颜色 -->
android:thumbTintMode="src_in"           <!-- 着色模式 -->
android:progressBackgroundTint="#E0E0E0" <!-- 背景颜色 -->
android:splitTrack="false"               <!-- 不要分割轨道(常见需求) -->

5. 常见问题 & 解决方案(2025 现状)

  • Thumb 不居中thumbOffset="0dp" + 确保 thumb drawable 宽高一致
  • 触摸区域太小minHeightmaxHeight 设为 40–60dp
  • 进度条不圆角 → 必须在 shape / layer-list 里都设置 corners
  • API < 21 渐变无效 → 用 layer-list + scale 模拟
  • 想完全自定义(不继承 SeekBar) → 推荐用 Slider(Material 3)或 RangeSlider,但 SeekBar 兼容性仍最强

需要哪种风格的完整代码示例?

  • 纯 XML 渐变圆角(最简单)
  • Thumb 带数字(最常用)
  • 垂直 SeekBar
  • 带刻度线的音量条
  • Material You 风格动态颜色

告诉我需求,我直接给你可复制的完整代码!

文章已创建 3890

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部