一、控件介绍
SeekBar控件是Android原生组件之一,用于选择连续的数据或者块数据。一般情况下,SeekBar控件都是用来实现调节音量大小、颜色、亮度等操作。但是,在实际开发中,我们会发现自带的SeekBar样式不够美观、不够适用。因此,本文将介绍如何自定义SeekBar控件,实现控件的样式和功能更加多样化。
二、自定义SeekBar的基本步骤
自定义SeekBar的基本步骤如下:
1、继承SeekBar,重写构造函数、绘制方法、触摸事件等方法;
2、定义SeekBar需要用到的属性;
3、在布局文件中引入自定义的SeekBar。
三、自定义SeekBar的具体实现
1. 自定义SeekBar属性的定义
首先,我们需要定义需要用到的SeekBar属性。
<declare-styleable name="MySeekBar"> <attr name="thumb" format="reference" /> <attr name="progressColor" format="color" /> <attr name="progressBackground" format="color" /> <attr name="seekBarHeight" format="dimension" /></declare-styleable>
其中,thumb
属性用于设置SeekBar的把手图像,progressColor
属性用于设置SeekBar填充区域的颜色,progressBackground
属性用于设置SeekBar未填充区域的颜色,seekBarHeight
属性用于设置SeekBar的高度。
2. 自定义SeekBar的绘制过程
接下来,我们需要重写SeekBar的onMeasure()
、onDraw()
和onTouchEvent()
方法。
2.1 onMeasure方法:测量SeekBar的大小
@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = MeasureSpec.getSize(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); setMeasuredDimension(width, height);}
通过重写onMeasure()
方法,我们可以测量SeekBar的大小,并将其设置为期望的大小。
2.2 onDraw方法:绘制SeekBar的基本属性
@Overrideprotected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); int width = getWidth(); int height = getHeight(); float thumbX = getThumbPosX(); // 绘制背景 RectF rectBackground = new RectF(0, height / 2 - seekBarHeight / 2, width, height / 2 + seekBarHeight / 2); paint.setColor(progressBackground); canvas.drawRoundRect(rectBackground, height / 2, height / 2, paint); // 绘制填充区域 float progressEnd = thumbX + getPaddingLeft(); RectF rectProgress = new RectF(0, height / 2 - seekBarHeight / 2, progressEnd, height / 2 + seekBarHeight / 2); paint.setColor(progressColor); canvas.drawRoundRect(rectProgress, height / 2, height / 2, paint); // 绘制把手图像 canvas.drawBitmap(thumbBitmap, thumbX, height / 2 - thumbBitmap.getHeight() / 2, paint);}
onDraw()
方法是SeekBar的绘制核心方法,我们可以在该方法中实现SeekBar的基本绘制,包括背景、填充区域和把手图像等内容。
2.3 onTouchEvent方法:监听SeekBar的触摸事件
@Overridepublic boolean onTouchEvent(MotionEvent event) { if (!isEnabled()) { return false; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touchDownX = event.getX(); break; case MotionEvent.ACTION_MOVE: float touchMoveX = event.getX(); float touchDelta = touchMoveX - touchDownX; touchDownX = touchMoveX; int thumbPosX = (int) (getThumbPosX() + touchDelta); int maxRange = getWidth() - getPaddingLeft() - getPaddingRight(); int seekBarWidth = thumbBitmap.getWidth(); thumbPosX = Math.max(thumbPosX, 0); thumbPosX = Math.min(thumbPosX, maxRange); setProgress(thumbPosX * getMax() / (maxRange - seekBarWidth)); break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_CANCEL: break; } return true;}
onTouchEvent()
方法是SeekBar的触摸事件处理方法,通过监听触摸事件的四种状态,我们可以实时更新SeekBar的视图状态。
3. 自定义SeekBar的样式
3.1 基本样式
<com.example.MySeekBar android:id="@+id/mySeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" app:thumb="@drawable/ic_thumb" app:progressColor="@color/colorAccent" app:progressBackground="@color/colorPrimary" app:seekBarHeight="20dp" />
通过设置app:thumb
、app:progressColor
和app:progressBackground
等属性,我们可以实现SeekBar的基本样式。
3.2 高级样式
<com.example.MySeekBar android:id="@+id/mySeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" app:thumb="@drawable/ic_thumb" app:progressColor="@color/colorAccent" app:progressBackground="@color/colorPrimary" app:seekBarHeight="20dp" style="?android:attr/progressBarStyleHorizontal" />
除了基本样式外,我们还可以通过设置style="?android:attr/progressBarStyleHorizontal"
属性,使得SeekBar的样式与系统默认的样式保持一致,效果更加美观。
四、完整代码示例
public class MySeekBar extends SeekBar { private Paint paint; private Bitmap thumbBitmap; private int progressColor; private int progressBackground; private int seekBarHeight; private float touchDownX; public MySeekBar(Context context) { super(context); setup(); } public MySeekBar(Context context, AttributeSet attrs) { super(context, attrs); setup(attrs); } public MySeekBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setup(attrs); } private void setup() { paint = new Paint(Paint.ANTI_ALIAS_FLAG); thumbBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_thumb); } private void setup(AttributeSet attrs) { paint = new Paint(Paint.ANTI_ALIAS_FLAG); thumbBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_thumb); TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MySeekBar); progressColor = typedArray.getColor(R.styleable.MySeekBar_progressColor, Color.RED); progressBackground = typedArray.getColor(R.styleable.MySeekBar_progressBackground, Color.GRAY); seekBarHeight = (int) typedArray.getDimension(R.styleable.MySeekBar_seekBarHeight, 10); typedArray.recycle(); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = MeasureSpec.getSize(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); setMeasuredDimension(width, height); } @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); int width = getWidth(); int height = getHeight(); float thumbX = getThumbPosX(); // 绘制背景 RectF rectBackground = new RectF(0, height / 2 - seekBarHeight / 2, width, height / 2 + seekBarHeight / 2); paint.setColor(progressBackground); canvas.drawRoundRect(rectBackground, height / 2, height / 2, paint); // 绘制填充区域 float progressEnd = thumbX + getPaddingLeft(); RectF rectProgress = new RectF(0, height / 2 - seekBarHeight / 2, progressEnd, height / 2 + seekBarHeight / 2); paint.setColor(progressColor); canvas.drawRoundRect(rectProgress, height / 2, height / 2, paint); // 绘制把手图像 canvas.drawBitmap(thumbBitmap, thumbX, height / 2 - thumbBitmap.getHeight() / 2, paint); } @Override public boolean onTouchEvent(MotionEvent event) { if (!isEnabled()) { return false; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touchDownX = event.getX(); break; case MotionEvent.ACTION_MOVE: float touchMoveX = event.getX(); float touchDelta = touchMoveX - touchDownX; touchDownX = touchMoveX; int thumbPosX = (int) (getThumbPosX() + touchDelta); int maxRange = getWidth() - getPaddingLeft() - getPaddingRight(); int seekBarWidth = thumbBitmap.getWidth(); thumbPosX = Math.max(thumbPosX, 0); thumbPosX = Math.min(thumbPosX, maxRange); setProgress(thumbPosX * getMax() / (maxRange - seekBarWidth)); break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_CANCEL: break; } return true; } private float getThumbPosX() { int width = getWidth() - getPaddingLeft() - getPaddingRight(); int seekBarWidth = thumbBitmap.getWidth(); float ratio = (float) getProgress() / (float) getMax(); return width * ratio; }}
<declare-styleable name="MySeekBar"> <attr name="thumb" format="reference" /> <attr name="progressColor" format="color" /> <attr name="progressBackground" format="color" /> <attr name="seekBarHeight" format="dimension" /></declare-styleable>
<com.example.MySeekBar android:id="@+id/mySeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" app:thumb="@drawable/ic_thumb" app:progressColor="@color/colorAccent" app:progressBackground="@color/colorPrimary" app:seekBarHeight="20dp" />
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/235890.html