一、控件介紹
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/zh-hk/n/235890.html