android:layout_width ="match_parent" android:layout_height ="wrap_content" android:max ="200" android:maxHeight ="3dp" android:minHeight ="3dp" android:progressDrawable ="@drawable/seekbar_bg" android:thumb ="@drawable/seekbar_thumb_bg" />

注意,如果你发现进度的高度或者宽度设置后依然很大,可以尝试使用 maxHeight与minHeight 来调整

xml属性:

  • android:max="200"                                                         设置进度最大值
  • android:progressDrawable="@drawable/seekbar_bg"  设置进度条的背景
  • android:thumb="@drawable/seekbar_thumb_bg"         设置进度条上圆点的背景
  • android:progress="10"                                                   设置当前进度值
  • android:min="0"                                                              设置最小值
  • android:splitTrack="false"                                              设置滑块圆点是否背景透明,在用图片设置thumb后,thumb的四周可能会出现正方形的白色背景。设置此属性可以取消这个背景
  • android:padding=“0dp” 请注意 ,SeekBar 实际上是有内边距的,如果你需要填充满效果就需要设置成0dp。另外如果你需要圆点比今天背景大,也是调整这个内边距
  • setProgress(int value) 设置滑块的位置
  • setMax(int value) 设置进度条的最大长度
  • setOnSeekBarChangeListener(OnSeekBarChangeListener l)这个主要是监听进度改变 里面包含3个回调方法: onProgressChanged 进度条变化 onStartTrackingTouch (SeekBar seekBar) 监听开始拖动滚动条时的操作 onStopTrackingTouch (SeekBar seekBar) 监听停止拖动滚动条的操作
  • setSecondaryProgress(int secondaryProgress) 设置缓冲的进度
  • setProgressDrawable(Drawable d) 在代码上设置进度条背景, 请注意 ,这里可以直接设置GradientDrawable或者 Drawable 。但是,设置后只会成为背景。如果需要有进度背景那就需要导入LayerDrawable。
  • <?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>
                <solid android:color="#ff51495e"/>
            </shape>
        </item>
        <item android:id="@android:id/secondaryProgress">
                <shape>
                    <solid android:color="#f9062a"/>
                </shape>
            </clip>
        </item>
        <item android:id="@android:id/progress">
                <shape>
                    <solid android:color="#2db334"/>
                </shape>
            </clip>
        </item>
    </layer-list>

    根据属性解释一下3个背景的对应功能,原则上如果你不需要显示预加载的功能,可以将 @android:id/secondaryProgress 设置为透明,或者不写

    android:id ="@android:id/background" 是没有如何拖动或者设置的背景, 请注意! 这个属性下面是没有用 <clip> 包裹的,如果不小心包裹了会出现没有背景的bug

    android:id ="@android:id/secondaryProgress" 是次级进度背景,类似你在看视频的时候,视频的进度条会有预加载的进度. 请注意! 这个属性下面是用<clip>包裹的,如果没有包裹 <clip>就 会出现进度条没有颜色的bug

    android:id ="@android:id/progress" 是主进度背景,就是你看视频的时候当前看到哪里的进度条背景. 请注意! 这个属性下面是用<clip>包裹的,如果没有包裹 <clip> 会出现进度条没有颜色的bug

    另外,进度条背景还支持设置伸缩方向,横竖方向与自定义矢量图,可以参考如下设置:

        <item android:id="@android:id/progress">
            <clip android:drawable="@drawable/ic_curtain"
                android:gravity="right"
                android:clipOrientation="horizontal">
            </clip>
        </item>

    进度条的圆点背景

    seekbar_thumb_bg.xml

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <!--获取焦点和没有按下的时候-->
        <item android:drawable="@drawable/seekbar_thumb_normal" android:state_focused="true" android:state_pressed="false"/>
        <!--获取焦点但按下的时候-->
        <item android:drawable="@drawable/seekbar_thumb_pressed" android:state_focused="true" android:state_pressed="true"/>
        <!--没有获取焦点按下的时候-->
        <item android:drawable="@drawable/seekbar_thumb_pressed" android:state_focused="false" android:state_pressed="true"/>
        <!--默认的时候-->
        <item android:drawable="@drawable/seekbar_thumb_normal"/>
    </selector>

    在代码上设置的监听

    mVideoSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
             //进度变化回调
             //fromUser 表示改变这个进度的这个操作来自用户,这个布尔值可以区分是代码上改变的进度还是,用户操作后改变的进度
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
              //开始触摸移动进度条
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
              //停止触摸移动进度条
    

    进度条圆点偏移

    如果你需要进度条圆点能超出进度条就需要将thumbOffset属性设置超出距离,反之如果你希望圆点永远不会超出进度条只需要设置为0dp

    android:thumbOffset="0dp"

    点子:自定义实现只允许拖拽不允许点击的seekbar进度条

     oldProgress = mSeekBar.getProgress();
            mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
                    if(progress > oldProgress + 3 || progress < oldProgress - 3){
                        seekBar.setProgress(oldProgress);
                        return;
                    seekBar.setProgress(progress);
                    oldProgress = progress;
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
    

    设置Thumb大小

        fun setThumbSize(){
            val bitmap = BitmapFactory.decodeResource(resources, R.mipmap.main_ic_vehicle_1)
            val dp238 = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 238f, resources.displayMetrics).toInt()
            val dp108 = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 108f, resources.displayMetrics).toInt()
            val thumb: Bitmap = Bitmap.createScaledBitmap(bitmap, dp238, dp108, true) //设置大小
            val d = BitmapDrawable(thumb)
            val bitmap1 = d.bitmap
            if (bitmap1.density == Bitmap.DENSITY_NONE) {
                d.setTargetDensity(resources.getDisplayMetrics())
            val drawable: Drawable = d
            mBinding.seekBar.thumb = drawable
    

    点子:将SeekBar进度条竖立

    在百度里有很多SeekBar竖立的例子,都是重新实现onDraw方法将画布旋转,但是我觉得那些都是化简为繁,也没深刻理解View这个基础类的强大之处,我的方式就是完美利用View的旋转属性

    请注意,这里有两种做法:

    第一种适合一些页面简单的地方,直接将SeekBar 旋转,优点是不需要布局嵌套了,但是需要小心翼翼调试好位置.

    第二种更适合进度条的形式,那就是在SeekBar外面套一个ConstraintLayout,然后将SeekBar在旋转. 这种方式可以适合在一些复杂的页面中.

    直接将SeekBar 旋转,优点是不需要布局嵌套了,但是需要小心翼翼调试好位置.适合一些简单的地方

    activity布局

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        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"
        android:background="@color/color_black_1"
        tools:context=".function.setting.system.view.SetScreenTimeoutActivity">
        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="76dp"
            android:text="@string/off_screen_time"
            android:textColor="@color/ColorWhite"
            android:textSize="22sp"
            android:gravity="center"
            android:background="@color/black"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"/>
        <ImageView
            android:id="@+id/back"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:src="@mipmap/img_back_arrow"
            android:paddingLeft="20dp"
            app:layout_constraintTop_toTopOf="@id/title"
            app:layout_constraintBottom_toBottomOf="@id/title"
            app:layout_constraintLeft_toLeftOf="parent"/>
        <ImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="100dp"
            android:src="@drawable/ic_screen_timeout"
            app:layout_constraintTop_toBottomOf="@id/title"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"/>
        <SeekBar
            android:id="@+id/seek_bar"
            android:layout_width="300dp"
            android:layout_height="70dp"
            android:rotationX="0.5"
            android:rotationY="0.5"
            android:rotation="270"
            android:thumb="@null"
            android:layout_marginTop="135dp"
            android:progressDrawable="@drawable/bg_seekbar"
            android:max="6"
            app:layout_constraintTop_toBottomOf="@id/icon"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"/>
        <ImageView
            android:id="@+id/add_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_add"
            android:layout_marginTop="55dp"
            app:layout_constraintLeft_toLeftOf="@id/seek_bar"
            app:layout_constraintRight_toRightOf="@id/seek_bar"
            app:layout_constraintTop_toBottomOf="@id/icon"/>
        <ImageView
            android:id="@+id/reduce_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_reduce"
            android:layout_marginTop="195dp"
            app:layout_constraintTop_toBottomOf="@id/add_icon"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"/>
        <TextView
            android:id="@+id/current_select_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="340dp"
            android:textSize="22sp"
            android:textColor="@color/ColorWhite"
            app:layout_constraintTop_toBottomOf="@id/icon"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"/>
    </androidx.constraintlayout.widget.ConstraintLayout>

    这样里有一个需要注意的点,就是高度和宽度其实是互换的关系了.

    bg_seekbar.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">
                <size android:width="300dp" android:height="70dp"/>
                <solid android:color="#575757"/>
                <corners android:radius="88dp"/>
            </shape>
        </item>
        <item android:id="@android:id/secondaryProgress">
                <shape>
                    <solid android:color="#575757"/>
                </shape>
            </clip>
        </item>
        <item android:id="@android:id/progress">
                <shape android:shape="rectangle">
                    <size android:width="300dp" android:height="70dp"/>
                    <solid android:color="#FFFFFF"/>
                    <corners android:radius="88dp"/>
                </shape>
            </clip>
        </item>
    </layer-list>

    思想上与第一种一样,关键区别是外部嵌套一个ConstraintLayout用于控制布局旋转后的位置大小.

    这种方式更适合进度条的形式,SeekBar外面套ConstraintLayout,然后将SeekBar在旋转. 这种方式可以适合在一些许多View需要配合的页面中. ,关键参考如下:

    这里的关键代码就是:app:layout_constraintDimensionRatio="1:1"   其中构思,请自行品味

    另外请注意,这里的thumb也会被旋转你需要准备一个相反旋转的thumb图片

     <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/unlockLayout"
            android:layout_width="69dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/layout">
            <SeekBar
                android:id="@+id/seekBar"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:rotationX="0.5"
                android:rotationY="0.5"
                android:rotation="90"
                android:paddingStart="50dp"
                android:paddingEnd="50dp"
                android:max="100"
                android:thumb="@drawable/snake_ic_lock_1"
                android:progressDrawable="@drawable/snake_seekbar_open_lock"
                app:layout_constraintDimensionRatio="1:1"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"/>
        </androidx.constraintlayout.widget.ConstraintLayout>

    点子:实现一个多色阶渐变进度条(颜色取值进度条)

    颜色取值的部分不说明,这个可以根据progress的位置来自定义取颜色值,这里重点说明的是怎么实现多色阶的渐变的背景。

    说明下为什么用代码实现,因为xml的shape属性根本不支持这么多颜色的渐变,在xml上的shape的gradient属性只支持三色阶渐变。当然,如果你直接放矢量图作为渐变色背景,那就不需要参考下面代码了。但是渐变色背景不能是位图,只能是矢量图。

    如果你不太了解GradientDrawable,可以参考我这篇博客:https://www.cnblogs.com/guanxinjing/p/11142599.html

            int[] colors = {Color.parseColor("#FF0000")
                    , Color.parseColor("#FF00FF")
                    , Color.parseColor("#0000FF")
                    , Color.parseColor("#00FFFF")
                    , Color.parseColor("#00FF00")
                    , Color.parseColor("#FFFF00")
                    , Color.parseColor("#FF0000")};
            GradientDrawable gradientDrawable = new GradientDrawable();
            gradientDrawable.setShape(GradientDrawable.RECTANGLE);
            gradientDrawable.setColors(colors); //添加颜色组
            gradientDrawable.setCornerRadius(UnitConversionUtil.dip2px(getContext(), 10));
            gradientDrawable.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);//设置渐变方向
            gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);//设置线性渐变
            gradientDrawable.setDither(true);
            Drawable[] drawables = {gradientDrawable};
            LayerDrawable layerDrawable = new LayerDrawable(drawables);
            layerDrawable.setId(0, android.R.id.background);
            mColorSeekBar.setProgressDrawable(layerDrawable);

    点子:Thumb带文字

    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.MotionEvent;
    import android.widget.SeekBar;
    import androidx.annotation.ColorRes;
    import com.lwlx.ui.main.R;
    @SuppressLint("AppCompatCustomView")
    public class TextSeekBar extends SeekBar {
        private Paint mPaint = new Paint();
        private float x;
        private float mTextSize = 18f;
        private int mColorId = R.color.main_color_9F621B;
        private float mWidth = 0f;
        private float mHeight = 0f;
        public TextSeekBar(Context context) {
            super(context);
            init();
        public TextSeekBar(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        public TextSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        public TextSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            init();
        private void init() {
            mPaint.setColor(getResources().getColor(mColorId));
            mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize, getResources().getDisplayMetrics()));
            mPaint.setTextAlign(Paint.Align.CENTER);
            mPaint.setStrokeWidth(15);
        public void setTextSize(float textSize) {
            this.mTextSize = textSize;
            invalidate();
        public void setTextColor(@ColorRes int id) {
            mColorId = id;
            invalidate();
        @Override
        protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            mWidth = MeasureSpec.getSize(widthMeasureSpec);
            mHeight = MeasureSpec.getSize(heightMeasureSpec);
            x = getProgress() * mWidth / 100 + getX();
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                x = event.getX();
            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                x = event.getX();
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
                x = event.getX();
            if (x < 0) {
                x = 0 + getPaddingLeft();
            } else if (x > mWidth) {
                x = mWidth - getPaddingRight();
            return super.onTouchEvent(event);
        @Override
        protected synchronized void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            float y = (mHeight - (getPaddingTop() + getPaddingBottom())) / 2;
            canvas.drawText(String.valueOf(getProgress()), x, y + 5, mPaint);