SeekBar的几种常见用法

SeekBar的几种常见用法本文介绍了 Android 中 SeekBar 的基本用法 包括水平样式 属性设置 布局编写和代码示例

大家好,欢迎来到IT知识分享网。


前言

SeekBar是Android的常用控件之一,简单总结下几种用法。

一、SeekBar基础用法

SeekBar是ProgressBar的扩展,是一个可以拖动的进度条,这样用户就可以通过拖动控制条来改变进度。系统默认只有水平样式。

1、水平样式

在这里插入图片描述

2、常用属性

  1. 设置进度条范围最大值
    android:max=“”
  2. 设置进度条范围最小值
    android:min=“”
  3. 设置当前进度值
    android:progress=“”
  4. 设置第二进度值(类似缓冲进度)
    android:secondaryProgress =“”
  5. 设置进度条的图片
    android:progressDrawable = “”
  6. 设置进度条的滑块图片
    android:thumb = “”

2、布局写法

 <SeekBar android:id="@+id/sb_number" android:layout_marginStart="@dimen/x38" android:layout_marginEnd="@dimen/x42" android:background="@null" android:splitTrack="false" android:layout_width="@dimen/x540" android:layout_height="wrap_content" android:maxHeight="@dimen/x10" android:progressDrawable="@drawable/seekbar_volume" android:thumb="@drawable/icon_seekbar_thumb"/> 

3、代码调用

 SeekBar seekBar = contentView.findViewById(R.id.sb_number); seekBar.setProgress(100); seekBar.setMin(0); seekBar.setMax(finalMaxTypeVolume); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 
     @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 
     // 进度变化时的回调 } @Override public void onStartTrackingTouch(SeekBar seekBar) { 
     // 开始拖动时的回调 } @Override public void onStopTrackingTouch(SeekBar seekBar) { 
     // 停止拖动时的回调 } }); 

二、垂直seekBar

默认的SeekBar没有设置方向的功能,垂直方向需要重新SeekBar.

1.关键代码,重新onDraw方法,将控件旋转90度

 protected void onDraw(Canvas c) { 
     c.rotate(-90); c.translate(-getHeight(), 0); super.onDraw(c); } 

三、圆弧seekBar

圆弧seekBar可以用来在复杂的界面使用,相对代码更加复杂,本文方法自定义view绘制。

1. 自定义圆弧SeekBar

 / * 圆弧 SeekBar */ public class ArcSeekBarPro extends View { 
     / * 画笔 */ private Paint mPaint; / * 笔画描边的宽度 */ private float mStrokeWidth; private Paint.Cap mStrokeCap = Paint.Cap.ROUND; / * 默认的控件宽度,也是圆弧直径 */ private int defaultArcDiameter; / * 开始角度 */ private int mStartAngle = 0; / * 路径角度 */ private int mSweepAngle = 30; / * 圆心坐标x */ private float mCircleCenterX; / * 圆心坐标y */ private float mCircleCenterY; / * 弧形 正常颜色 */ private int mNormalColor = 0x80D0D4D9; / * 进度颜色 */ private int mProgressColor = 0x99FFFFFF; / * 半径 */ private float mRadius; / * 最大进度 */ private int mMax = 10; / * 当前进度 */ private int mProgress = 0; / * 进度百分比 */ private int mProgressPercent; private Bitmap mThumbBitmap; private Matrix mMatrix; / * 拖动按钮的画笔宽度 */ private float mThumbStrokeWidth; / * 拖动按钮的颜色 */ private int mThumbColor = 0xFFD5BDAD; / * 拖动按钮的半径 */ private float mThumbRadius; / * 拖动按钮的中心点X坐标 */ private float mThumbCenterX; / * 拖动按钮的中心点Y坐标 */ private float mThumbCenterY; / * 触摸时可偏移距离 */ private float mAllowableOffsets; / * 触摸时按钮半径放大量 */ private float mThumbRadiusEnlarges; / * 是否显示拖动按钮 */ private boolean isShowThumb = true; / * 手势,用来处理点击事件 */ private GestureDetector mDetector; / * 是否可以拖拽 */ private boolean isCanDrag = false; / * 是否启用拖拽改变进度 */ private boolean isEnabledDrag = true; / * 是否启用点击改变进度 */ private boolean isEnabledSingle = true; private OnChangeListener mOnChangeListener; public ArcSeekBarPro(Context context) { 
     this(context, null); } public ArcSeekBarPro(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); } public ArcSeekBarPro(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { 
     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ArcSeekBarPro); mThumbBitmap = Utils.loadBitmap(R.drawable.icon_seekbar_pro_thumb, context); mMatrix = new Matrix(); DisplayMetrics displayMetrics = getDisplayMetrics(); defaultArcDiameter = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.arc_diameter), getDisplayMetrics()); mStrokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.eac_control_thumb), displayMetrics); mThumbRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.thumb_drawable_radius), displayMetrics); mThumbStrokeWidth = mThumbRadius; mAllowableOffsets = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, displayMetrics); mThumbRadiusEnlarges = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, displayMetrics); int size = a.getIndexCount(); for (int i = 0; i < size; i++) { 
     int attr = a.getIndex(i); if (attr == R.styleable.ArcSeekBarPro_arcStrokeWidth) { 
     mStrokeWidth = a.getDimension(attr, mStrokeWidth); } else if (attr == R.styleable.ArcSeekBarPro_arcStrokeCap) { 
     mStrokeCap = getStrokeCap(a.getInt(attr, 3)); } else if (attr == R.styleable.ArcSeekBarPro_arcNormalColor) { 
     mNormalColor = a.getColor(attr, mNormalColor); } else if (attr == R.styleable.ArcSeekBarPro_arcProgressColor) { 
     mProgressColor = a.getColor(attr, mProgressColor); } else if (attr == R.styleable.ArcSeekBarPro_arcStartAngle) { 
     mStartAngle = a.getInt(attr, mStartAngle); } else if (attr == R.styleable.ArcSeekBarPro_arcSweepAngle) { 
     mSweepAngle = a.getInt(attr, mSweepAngle); } else if (attr == R.styleable.ArcSeekBarPro_arcMax) { 
     int max = a.getInt(attr, mMax); if (max > 0) { 
     mMax = max; } } else if (attr == R.styleable.ArcSeekBarPro_arcProgress) { 
     mProgress = a.getInt(attr, mProgress); } else if (attr == R.styleable.ArcSeekBarPro_arcThumbStrokeWidth) { 
     mThumbStrokeWidth = a.getDimension(attr, mThumbStrokeWidth); } else if (attr == R.styleable.ArcSeekBarPro_arcThumbColor) { 
     mThumbColor = a.getColor(attr, mThumbColor); } else if (attr == R.styleable.ArcSeekBarPro_arcThumbRadius) { 
     mThumbRadius = a.getDimension(attr, mThumbRadius); } else if (attr == R.styleable.ArcSeekBarPro_arcThumbRadiusEnlarges) { 
     mThumbRadiusEnlarges = a.getDimension(attr, mThumbRadiusEnlarges); } else if (attr == R.styleable.ArcSeekBarPro_arcShowThumb) { 
     isShowThumb = a.getBoolean(attr, isShowThumb); } else if (attr == R.styleable.ArcSeekBarPro_arcAllowableOffsets) { 
     mAllowableOffsets = a.getDimension(attr, mAllowableOffsets); } else if (attr == R.styleable.ArcSeekBarPro_arcEnabledDrag) { 
     isEnabledDrag = a.getBoolean(attr, true); } else if (attr == R.styleable.ArcSeekBarPro_arcEnabledSingle) { 
     isEnabledSingle = a.getBoolean(attr, true); } } a.recycle(); mProgressPercent = (int) (mProgress * 100.0f / mMax); mPaint = new Paint(); mDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { 
     @Override public boolean onSingleTapUp(MotionEvent event) { 
     if (isInArc(event.getX(), event.getY())) { 
     updateDragThumb(event.getX(), event.getY(), true); if (mOnChangeListener != null) { 
     mOnChangeListener.onSingleTapUp(); } return true; } return super.onSingleTapUp(event); } }); } private Paint.Cap getStrokeCap(int value) { 
     switch (value) { 
     case 1: return Paint.Cap.BUTT; case 2: return Paint.Cap.SQUARE; default: return Paint.Cap.ROUND; } } private DisplayMetrics getDisplayMetrics() { 
     return getResources().getDisplayMetrics(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = measureHandler(widthMeasureSpec, defaultArcDiameter); int height = measureHandler(heightMeasureSpec, defaultArcDiameter); //圆心坐标 mCircleCenterX = (width + getPaddingLeft() - getPaddingRight()) / 2.0f; mCircleCenterY = (height + getPaddingTop() - getPaddingBottom()) / 2.0f; //计算间距 int padding = Math.max(getPaddingLeft() + getPaddingRight(), getPaddingTop() + getPaddingBottom()); //半径=视图宽度-横向或纵向内间距值 - 画笔宽度 mRadius = (width - padding - Math.max(mStrokeWidth, mThumbStrokeWidth)) / 2.0f - mThumbRadius; setMeasuredDimension(width, height); } / * 测量 * * @param measureSpec * @param defaultSize * @return */ private int measureHandler(int measureSpec, int defaultSize) { 
     int result = defaultSize; int measureMode = MeasureSpec.getMode(measureSpec); int measureSize = MeasureSpec.getSize(measureSpec); if (measureMode == MeasureSpec.EXACTLY) { 
     result = measureSize; } else if (measureMode == MeasureSpec.AT_MOST) { 
     result = Math.min(defaultSize, measureSize); } return result; } @Override protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); drawArc(canvas); drawThumb(canvas); } / * 绘制弧形 * * @param canvas */ private void drawArc(Canvas canvas) { 
     mPaint.reset(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(mStrokeWidth); mPaint.setShader(null); mPaint.setStrokeCap(mStrokeCap); //进度圆半径 float diameter = mRadius * 2; float startX = mCircleCenterX - mRadius; float startY = mCircleCenterY - mRadius; RectF rectF1 = new RectF(startX, startY, startX + diameter, startY + diameter); if (mNormalColor != 0) { 
     mPaint.setColor(mNormalColor); //绘制底层弧形 canvas.drawArc(rectF1, mStartAngle, mSweepAngle, false, mPaint); } mPaint.setColor(mProgressColor); float ratio = getRatio(); if (ratio != 0) { 
     //绘制当前进度弧形 canvas.drawArc(rectF1, mStartAngle, mSweepAngle * ratio, false, mPaint); } } private void drawThumb(Canvas canvas) { 
     if (isShowThumb) { 
     mPaint.reset(); // mPaint.setAntiAlias(true); // mPaint.setStyle(Paint.Style.FILL_AND_STROKE); // mPaint.setStrokeWidth(mThumbStrokeWidth); // mPaint.setColor(mThumbColor); float thumbAngle = mStartAngle + mSweepAngle * getRatio(); //已知圆心,半径,角度,求圆上的点坐标 mThumbCenterX = (float) (mCircleCenterX + mRadius * Math.cos(Math.toRadians(thumbAngle))); mThumbCenterY = (float) (mCircleCenterY + mRadius * Math.sin(Math.toRadians(thumbAngle))); // if (isCanDrag) { 
     // canvas.drawCircle(mThumbCenterX, mThumbCenterY, mThumbRadius + mThumbRadiusEnlarges, mPaint); // } else { 
     // canvas.drawCircle(mThumbCenterX, mThumbCenterY, mThumbRadius, mPaint); // } if (null != mThumbBitmap) { 
     mMatrix.setTranslate(mThumbCenterX - mThumbRadius, mThumbCenterY - mThumbRadius); mMatrix.preScale(1, 1, 0, 0); mPaint.setAlpha(255); canvas.drawBitmap(mThumbBitmap, mMatrix, mPaint); } } } @Override public boolean onTouchEvent(MotionEvent event) { 
     if (isEnabledDrag) { 
     switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: checkCanDrag(event.getX(), event.getY()); break; case MotionEvent.ACTION_MOVE: if (isCanDrag) { 
     updateDragThumb(event.getX(), event.getY(), false); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: getParent().requestDisallowInterceptTouchEvent(false); if (mOnChangeListener != null) { 
     mOnChangeListener.onStopTrackingTouch(isCanDrag); } isCanDrag = false; invalidate(); break; } } if (isEnabledSingle) { 
     mDetector.onTouchEvent(event); } return isEnabledSingle || isEnabledDrag || super.onTouchEvent(event); } / * 判断坐标点是否在弧形上 * * @param x * @param y * @return */ private boolean isInArc(float x, float y) { 
     float distance = getDistance(mCircleCenterX, mCircleCenterY, x, y); if (Math.abs(distance - mRadius) <= mStrokeWidth / 2f + mAllowableOffsets) { 
     if (mSweepAngle < 360) { 
     float angle = (getTouchDegrees(x, y) + mStartAngle) % 360; if (mSweepAngle < 0) { 
     if (mStartAngle + mSweepAngle + 360 <= 360) { 
     return angle <= mStartAngle || angle >= (mStartAngle + mSweepAngle + 360) % 360; } else { 
     return angle <= mStartAngle && angle >= mStartAngle + mSweepAngle + 360; } } if (mStartAngle + mSweepAngle <= 360) { 
     return angle >= mStartAngle && angle <= mStartAngle + mSweepAngle; } else { 
     return angle >= mStartAngle || angle <= (mStartAngle + mSweepAngle) % 360; } } return true; } return false; } / * 获取两点间距离 * * @param x1 * @param y1 * @param x2 * @param y2 * @return */ private float getDistance(float x1, float y1, float x2, float y2) { 
     return (float) Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); } / * 更新多拽进度 * * @param x * @param y * @param isSingle */ private void updateDragThumb(float x, float y, boolean isSingle) { 
     int progress = getProgressForAngle(getTouchDegrees(x, y)); if (!isSingle) { 
     int tempProgressPercent = (int) (progress * 100.0f / mMax); //当滑动至至边界值时,增加进度校准机制 if (mProgressPercent < 10 && tempProgressPercent > 90) { 
     progress = 0; } else if (mProgressPercent > 90 && tempProgressPercent < 10) { 
     progress = mMax; } int progressPercent = (int) (progress * 100.0f / mMax); //拖动进度突变不允许超过30% if (Math.abs(progressPercent - mProgressPercent) > 30) { 
     return; } } setProgress(progress, true); } / * 通过弧度换算得到当前精度 * * @param angle * @return */ private int getProgressForAngle(float angle) { 
     int touchProgress = 0; if (mSweepAngle < 0) { 
     touchProgress = Math.round(1.0f * mMax / mSweepAngle * (angle - 360)); } else { 
     touchProgress = Math.round(1.0f * mMax / mSweepAngle * angle); } return touchProgress; } / * 获取触摸坐标的夹角度数 * * @param x * @param y * @return */ private float getTouchDegrees(float x, float y) { 
     float x1 = x - mCircleCenterX; float y1 = y - mCircleCenterY; //求触摸点弧形的夹角度数 float angle = (float) (Math.atan2(y1, x1) * 180 / Math.PI); angle -= mStartAngle; while (angle < 0) { 
     angle += 360; } return angle; } / * 检测是否可拖拽 * * @param x * @param y */ private void checkCanDrag(float x, float y) { 
     float distance = getDistance(mThumbCenterX, mThumbCenterY, x, y); isCanDrag = distance <= mThumbRadius + mAllowableOffsets; if (mOnChangeListener != null) { 
     mOnChangeListener.onStartTrackingTouch(isCanDrag); } invalidate(); } / * 进度比例 * * @return */ private float getRatio() { 
     return mProgress * 1.0f / mMax; } / * 设置最大进度 * * @param max */ public void setMax(int max) { 
     if (max > 0) { 
     this.mMax = max; invalidate(); } } / * 设置当前进度 * * @param progress */ public void setProgress(int progress) { 
     setProgress(progress, false); } private void setProgress(int progress, boolean fromUser) { 
     if (progress < 0) { 
     progress = 0; } else if (progress > mMax) { 
     progress = mMax; } this.mProgress = progress; mProgressPercent = (int) (mProgress * 100.0f / mMax); invalidate(); if (mOnChangeListener != null) { 
     mOnChangeListener.onProgressChanged(mProgress, mMax, fromUser); } } / * 设置正常颜色 * * @param color */ public void setNormalColor(int color) { 
     this.mNormalColor = color; invalidate(); } / * 设置进度颜色(纯色) * * @param color */ public void setProgressColor(int color) { 
     this.mProgressColor = color; invalidate(); } / * 设置进度颜色 * * @param resId */ public void setProgressColorResource(int resId) { 
     int color = getResources().getColor(resId); setProgressColor(color); } public int getStartAngle() { 
     return mStartAngle; } public int getSweepAngle() { 
     return mSweepAngle; } public float getCircleCenterX() { 
     return mCircleCenterX; } public float getCircleCenterY() { 
     return mCircleCenterY; } public float getRadius() { 
     return mRadius; } public int getMax() { 
     return mMax; } public int getProgress() { 
     return mProgress; } public float getThumbRadius() { 
     return mThumbRadius; } public float getThumbCenterX() { 
     return mThumbCenterX; } public float getThumbCenterY() { 
     return mThumbCenterY; } public float getAllowableOffsets() { 
     return mAllowableOffsets; } public boolean isEnabledDrag() { 
     return isEnabledDrag; } public boolean isEnabledSingle() { 
     return isEnabledSingle; } public boolean isShowThumb() { 
     return isShowThumb; } public float getThumbRadiusEnlarges() { 
     return mThumbRadiusEnlarges; } / * 触摸时按钮半径放大量 * * @param thumbRadiusEnlarges */ public void setThumbRadiusEnlarges(float thumbRadiusEnlarges) { 
     this.mThumbRadiusEnlarges = thumbRadiusEnlarges; } / * 是否显示拖动按钮 * * @param showThumb */ public void setShowThumb(boolean showThumb) { 
     isShowThumb = showThumb; invalidate(); } / * 触摸时可偏移距离:偏移量越大,触摸精度越小 * * @param allowableOffsets */ public void setAllowableOffsets(float allowableOffsets) { 
     this.mAllowableOffsets = allowableOffsets; } / * 是否启用拖拽 * * @param enabledDrag 默认为 true,为 false 时 相当于{@link android.widget.ProgressBar} */ public void setEnabledDrag(boolean enabledDrag) { 
     isEnabledDrag = enabledDrag; } / * 设置是否启用点击改变进度 * * @param enabledSingle */ public void setEnabledSingle(boolean enabledSingle) { 
     isEnabledSingle = enabledSingle; } / * 进度百分比 * * @return */ public int getProgressPercent() { 
     return mProgressPercent; } / * 设置进度改变监听 * * @param onChangeListener */ public void setOnChangeListener(OnChangeListener onChangeListener) { 
     this.mOnChangeListener = onChangeListener; } public interface OnChangeListener { 
     / * 跟踪触摸事件开始时回调此方法 {@link MotionEvent#ACTION_DOWN} * * @param isCanDrag */ void onStartTrackingTouch(boolean isCanDrag); / * 进度改变时回调此方法 * * @param progress * @param max * @param fromUser */ void onProgressChanged(int progress, int max, boolean fromUser); / * 跟踪触摸事件停止时回调此方法 {@link MotionEvent#ACTION_UP} */ void onStopTrackingTouch(boolean isCanDrag); / * 通过点击事件改变进度后回调此方法 {@link GestureDetector#GestureDetector#onSingleTapUp()} */ void onSingleTapUp(); } } 

三种SeekBar效果如图所示

在这里插入图片描述

三、常见问题

  1. 自定义图标滑到最小或者最大时,图标异常
 android:thumbOffset="0px" 
  1. 滑块间隔是否覆盖滑轨,系统默认是间隔
 android:splitTrack=false//默认为true 
  1. 解决 seekBar 宽度不撑满布局
 android:paddingStart="0dp" android:paddingEnd="0dp" 

四、参考链接

  • https://github.com/jenly1314/ArcSeekBar
  • https://blog.csdn.net/liosen/article/details/

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/129217.html

(0)
上一篇 2025-08-25 20:15
下一篇 2025-08-25 20:20

相关推荐

发表回复

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

关注微信