之前项目中由于滑块功能需要的SeekBar是继承自AppCompatSeekBar,发现坑还是蛮多的,所以自己简单撸了一个。
想法很简单:判断view的touch事件,move事件时候绘制滑块按钮和进度 。然后分别在down move up事件中仿照seekBar的回调一次把onStartTouch-onProgressChange-onStopTouch回调出来。具体代码如下:
package com.example.simatu.coordinatorlayout.widget; import android.content.Context; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.Nullable; import android.text.TextPaint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import com.example.simatu.coordinatorlayout.R; public class MyCustomSeekBar extends View { private Context mContext; private Paint mProgressPaint; private static final String DEFAULT_TYPE = "default"; private static final String SUCCESS_TYPE = "success"; private static final String WRONG_TYPE = "wrong"; private String mCurrentType = DEFAULT_TYPE; private float thumbCenterX; private int mThumbDrawable; private String mVerifyText; public void setOnProgressChangeListener(OnProgressChangeListener onProgressChangeListener) { this.onProgressChangeListener = onProgressChangeListener; } private OnProgressChangeListener onProgressChangeListener; public MyCustomSeekBar(Context context) { super(context); init(context); } public MyCustomSeekBar(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context); } public MyCustomSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { this.mContext = context; mVerifyText = context.getString(R.string.verifyText); mProgressPaint = new Paint(); thumbCenterX = dip2px(20f); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); Rect rect = new Rect(); Paint mTextPaint = new TextPaint(); mTextPaint.setTextSize(50f); int textLength = mVerifyText == null ? 0 : mVerifyText.length(); mTextPaint.getTextBounds(mVerifyText, 0, textLength, rect); int startX = getWidth() / 2; int startY = getHeight() / 2; //绘制滑块中的提示文字 canvas.drawText(mVerifyText, startX, startY, mTextPaint); canvas.restore(); mProgressPaint.setStyle(Paint.Style.FILL);//设置填充样式 //根据滑动时的手势或者验证的结果来绘制不同的按钮和进度颜色 switch (mCurrentType) { case DEFAULT_TYPE: mThumbDrawable = R.mipmap.slider_button_default; mProgressPaint.setColor(getResources().getColor(R.color.progress_default)); break; case SUCCESS_TYPE: mThumbDrawable = R.mipmap.slider_button_success; mProgressPaint.setColor(getResources().getColor(R.color.progress_success)); break; case WRONG_TYPE: mThumbDrawable = R.mipmap.slider_button_failed; mProgressPaint.setColor(getResources().getColor(R.color.progress_failed)); break; } //以按钮中心为标准画进度条和按钮 RectF rectF = new RectF(0, 0, thumbCenterX + dip2px(20f), 120); //这里top为0 bottom为控件高度 canvas.drawRoundRect(rectF, dip2px(8f), dip2px(8f), mProgressPaint); //绘制按钮 canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mThumbDrawable), thumbCenterX - dip2px(20f), 0, null); canvas.restore(); } @Override protected void onSizeChanged(int w, int h, int oldW, int oldH) { super.onSizeChanged(w, h, oldW, oldH); } @Override public boolean onTouchEvent(MotionEvent event) { //根据手势滑动 改变按钮的距离并且改变进度条的进度 // 这里的坐标只是相对于控件top 和left的距离 float downX; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); thumbCenterX = downX; if (thumbCenterX < dip2px(20f)) { thumbCenterX = dip2px(20f); if (null != onProgressChangeListener) { onProgressChangeListener.onStartTouch(this); } } break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); thumbCenterX = moveX; if (thumbCenterX >= dip2px(20f) || thumbCenterX <= getRight() - dip2px(20f)) { if (null != onProgressChangeListener) { int progress = (int) (moveX / getWidth()); onProgressChangeListener.onProgressChange(progress, this); } } if (thumbCenterX < dip2px(20f)) { thumbCenterX = dip2px(20f); } if (thumbCenterX >= getRight() - dip2px(20f)) { thumbCenterX = getRight() - dip2px(20f); } invalidate(); break; case MotionEvent.ACTION_UP: if (null != onProgressChangeListener) { onProgressChangeListener.onStopTouch(this); } break; } return true; } /** * 禁用点击非thumb按钮区域的点击事件 * * @param event * @return */ @Override public boolean dispatchTouchEvent(MotionEvent event) { //这个就是按钮的矩阵 Rect thumbRect = new Rect(((int) (thumbCenterX - dip2px(20f))), 0, ((int) (thumbCenterX + dip2px(20f))), 120); int thumbLeft = thumbRect.left; int thumbRight = thumbRect.right; int thumbTop = thumbRect.top; int thumbBottom = thumbRect.bottom; int eventX = (int) event.getX(); int eventY = (int) event.getY(); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (eventX <= thumbLeft || eventX >= thumbRight || eventY <= thumbTop || eventY >= thumbBottom) { return false; } } return super.dispatchTouchEvent(event); } /** * 重置进度为0 */ public void resetThumb() { thumbCenterX = dip2px(20f); mCurrentType = DEFAULT_TYPE; invalidate(); } public interface OnProgressChangeListener { void onStartTouch(MyCustomSeekBar seekBar); void onProgressChange(int progress, MyCustomSeekBar seekBar); void onStopTouch(MyCustomSeekBar seekBar); } public int dip2px(float dipValue) { return (int) (dipValue * getScreenScale() + 0.5f); } /** * The logical density of the display. * * @return float */ public float getScreenScale() { try { final float scale = mContext.getResources().getDisplayMetrics().density; return scale; } catch (Throwable e) { return 1; } } }