Android技术分享| 自定义View实现使用更方便的SeekBar

胸怀万里世界, 放眼无限未来。这篇文章主要讲述Android技术分享| 自定义View实现使用更方便的SeekBar相关的知识,希望能为你提供帮助。
前言
android中自带的SeekBar个人感觉用起来很麻烦,调整一些颜色之类的需要单独写一个XML文件,内容感觉也很啰嗦。刚好我们的白板Demo开发中需要用到SeekBar,所以干脆实现了一个满足基本功能的SeekBar,支持在xml布局中指定各种颜色属性,也支持代码动态设置颜色。用起来更顺心一些。
SeekBar的代码请查看Github地址:白板Demo,Demo地址请:点击这里
即拿即用,非常方便; p(记得将res/values/styles.xml中的属性一并复制走)
效果

Android技术分享| 自定义View实现使用更方便的SeekBar

文章图片

实现
由于不涉及到动画,这种自定义View做起来还是相当简单的。首先在res/values/styles.xml文件中定义好自己需要的属性,我这里贴上我定义的属性:
< declare-styleable name="SeekBarWidget"> < attr name="seek_maxProgress" format="integer" /> < !-- 最大progress --> < attr name="seek_minProgress" format="integer" /> < !-- 最小progress --> < attr name="seek_progress" format="integer" /> < !-- 当前progress(默认值) --> < attr name="seek_circleRadius" format="dimension" /> < !-- seekBar中间圆形的半径 --> < attr name="seek_circleStrokeWidth" format="dimension" /> < !-- seekBar中间圆形外的border --> < attr name="seek_lineHeight" format="dimension" /> < !-- lineHeight有点词不达意,其实是进度条的高度 --> < attr name="seek_backgroundColor" format="color" /> < !-- 进度条的背景色 --> < attr name="seek_circleStrokeColor" format="color" /> < !-- border的颜色 --> < attr name="seek_maxColor" format="color" /> < !-- 进度条的前景色 --> < attr name="seek_startColor" format="color" /> < !-- 如果需要渐变色则设置此属性,否则这条属性置空即可 --> < /declare-styleable>

属性定义好以后,在View的构造中解析一下:
public SeekBarWidget(Context context) this(context, null); public SeekBarWidget(Context context, @Nullable AttributeSet attrs) this(context, attrs, 0); public SeekBarWidget(Context context, @Nullable AttributeSet attrs, int defStyleAttr) super(context, attrs, defStyleAttr); if (null != attrs) TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.SeekBarWidget); minProgress = typedArray.getInt(R.styleable.SeekBarWidget_seek_minProgress, 0); maxProgress = typedArray.getInt(R.styleable.SeekBarWidget_seek_maxProgress, 100) - minProgress; progress = typedArray.getInt(R.styleable.SeekBarWidget_seek_progress, 0) - minProgress; if (progress < 0) progress = minProgress; circleRadius = typedArray.getDimension(R.styleable.SeekBarWidget_seek_circleRadius, 20f); circleStrokeWidth = typedArray.getDimension(R.styleable.SeekBarWidget_seek_circleStrokeWidth, 5f); lineHeight = typedArray.getDimension(R.styleable.SeekBarWidget_seek_lineHeight, 5f); backgroundColor = typedArray.getColor(R.styleable.SeekBarWidget_seek_backgroundColor, Color.parseColor("#F0F0F0")); circleStrokeColor = typedArray.getColor(R.styleable.SeekBarWidget_seek_circleStrokeColor, Color.WHITE); int maxColor = typedArray.getColor(R.styleable.SeekBarWidget_seek_maxColor, Color.RED); int startColor = typedArray.getColor(R.styleable.SeekBarWidget_seek_startColor, maxColor); colorTransition = new ColorTransition(startColor, maxColor); typedArray.recycle(); percentage = progress * 1.0f / maxProgress; horizontalPadding = circleRadius * 2 + circleStrokeWidth * 2 + getPaddingStart() + getPaddingEnd(); mPaddingLeft = horizontalPadding - getPaddingEnd() - circleRadius - circleStrokeWidth; return; maxProgress = 100; minProgress = 0; circleRadius = 20; circleStrokeWidth = 5; lineHeight = 5; backgroundColor = Color.parseColor("#F0F0F0"); colorTransition = new ColorTransition(Color.WHITE, Color.RED); circleStrokeColor = Color.WHITE; horizontalPadding = circleRadius * 2 + circleStrokeWidth * 2 + getPaddingStart() + getPaddingEnd(); mPaddingLeft = horizontalPadding - getPaddingEnd() - circleRadius - circleStrokeWidth;

接下来是onMeasureonDraw,由于我的应用场景宽高已经固定好了,所以没有写onMeasure,有需求的朋友可以自己实现一下~
而绘制的思路很简单:
  1. 先绘制一条背景色的线,线的高度由外部指定。(设置StrokeCap为ROUND)
  2. 再绘制一条前景色的线,线高度同样由外部指定,这里我读取的是同一个属性lineHeight,也可以根据需求不同设置不一样的高度; p
  3. 接下来绘制seekBar的圆,这里border也直接使用drawCircle来实现,先绘制border。(circleRadius + circleStrokeWidth / 2f)
  4. 最后绘制中间的圆
onDraw:
@Override protected void onDraw(Canvas canvas) final int width = (int) (getMeasuredWidth() - horizontalPadding); final int height = getMeasuredHeight(); paint.setColor(backgroundColor); paint.setStrokeWidth(lineHeight); paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setStrokeCap(Paint.Cap.ROUND); canvas.drawLine(mPaddingLeft, height > > 1, mPaddingLeft + width, height > > 1, paint); //float percentage = progress / maxProgress; int currColor = colorTransition.getValue(percentage); paint.setColor(currColor); canvas.drawLine(mPaddingLeft, height > > 1, mPaddingLeft + width * percentage, height > > 1, paint); // draw circle border paint.setColor(circleStrokeColor); canvas.drawCircle(mPaddingLeft + width * percentage, height > > 1, circleRadius + (circleStrokeWidth / 2f), paint); // draw circle inside color paint.setColor(currColor); canvas.drawCircle(mPaddingLeft + width * percentage, height > > 1, circleRadius, paint);

最后,处理一下onTouch事件。思路也很简单,从down、move、up事件中判断一下是否为横向滚动,是的话计算一下距离,更改progress进度并通知View重新绘制即可:
private float downX; private float downY; @Override public boolean onTouchEvent(MotionEvent event) boolean intercept = false; switch (event.getAction()) case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); intercept = true; break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); float xMove = Math.abs(moveX - downX) - Math.abs(moveY - downY); if (xMove > 0f) float hX = moveX - downX; boolean toLeft = hX < 0.0f; float movePercent = Math.abs(hX) / getMeasuredWidth(); if (percentage < 1.0f & & !toLeft) percentage += movePercent; else if (percentage > 0f & & toLeft) percentage -= movePercent; if (percentage < 0f) percentage = 0f; if (percentage > 1f) percentage = 1f; progress = (int) Math.floor(percentage * maxProgress); intercept = true; downX = moveX; downY = moveY; postInvalidate(); if (null != mListener & & beforeProgress != getProgress()) beforeProgress = getProgress(); mListener.onProgress(getProgress()); break; case MotionEvent.ACTION_UP: break; return intercept || super.onTouchEvent(event); //return true; @Override public boolean dispatchTouchEvent(MotionEvent event) getParent().requestDisallowInterceptTouchEvent(true); return super.dispatchTouchEvent(event);

OK,一个复制即用的自定义SeekBar便完成了。比官方原版的SeekBar使用起来顺眼多了(??ω?)?
(欢迎下载Demo玩一玩!Demo地址)
【Android技术分享| 自定义View实现使用更方便的SeekBar】
Android技术分享| 自定义View实现使用更方便的SeekBar

文章图片


    推荐阅读