最近在項(xiàng)目中遇到一個(gè)需要滑動(dòng)驗(yàn)證的功能,樣式如下:


????????? 在未滑動(dòng)時(shí)滑塊為箭頭形式,滑動(dòng)到末端后變?yōu)閷?duì)勾樣式,滑動(dòng)過的路徑變?yōu)榧t色,遇到問題當(dāng)然是先百度一番啦,沒有對(duì)象,只能面向百度編程了,結(jié)果弄了半天都沒找到合適的,大部分都是通過SeekBar來做的,但動(dòng)態(tài)設(shè)置thumb的時(shí)候滑到首尾上面的thumb總是被覆蓋掉一半,然后找了半天也沒得到解決,沒想到這東西資料這么少,沒辦法,只能自己來了,先看一下效果:



效果大概就是這個(gè)樣子,不是很完美,勉強(qiáng)夠用,沒滑到底松開會(huì)自動(dòng)回到起點(diǎn),
下面來說一下具體實(shí)現(xiàn):
1. 自定義VerifiSeekBar(就這個(gè)控件)繼承自View。
2.畫背景灰色圓角矩形,畫上方紅色圓角矩形,畫初始狀態(tài)滑塊(帶箭頭),畫結(jié)束狀態(tài)滑塊。
3.TouchEvent監(jiān)聽手勢,主要是X軸位置,根據(jù)屏幕上的坐標(biāo)動(dòng)態(tài)畫紅色矩形和滑塊
4.監(jiān)聽滑動(dòng)距離是否到最后,到最后后畫完成狀態(tài)滑塊(對(duì)勾)
思路就是這個(gè)樣子咯,思路對(duì)了的話,代碼就很好寫了,下面貼一下代碼,寫得不是很好,有啥不對(duì)的地方歡迎大家指教。
```
public class VerifiSeekBar extends View {
private Contextcontext;
? ? private Paintpaint;
? ? private int movex;
? ? private RectFbgRect;
? ? private RectFupRect;
? ? private BitmapinBitmap;
? ? private BitmapoutBitmap;
? ? private int bitmapWidth;
? ? private int bitmapHeight;
? ? //防止多次調(diào)用
? ? private boolean isNewdown =true;
? ? private OnSeekbarCompleListenneronSeekbarCompleListenner;
? ? public VerifiSeekBar(Context context) {
super(context);
? ? ? ? this.context = context;
? ? ? ? initView();
? ? }
public VerifiSeekBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
? ? ? ? this.context = context;
? ? ? ? initView();
? ? }
public VerifiSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
? ? ? ? this.context = context;
? ? ? ? initView();
? ? }
public void setProgress(int progress) {
movex = progress;
? ? ? ? invalidate();
? ? }
@Override
? ? protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
? ? ? ? paint.setColor(ContextCompat.getColor(context, R.color.seekbar_notclick));
? ? ? ? bgRect.set(0, 0, getWidth(), bitmapHeight + SizeUtils.dp2px(6));
? ? ? ? canvas.drawRoundRect(bgRect, SizeUtils.dp2px(5), SizeUtils.dp2px(5), paint);
? ? ? ? if (movex > getWidth()) {
movex = getWidth();
? ? ? ? }
if (movex <=0) {
movex =0;
? ? ? ? }
upRect.set(0, 0, movex, bitmapHeight + SizeUtils.dp2px(6));
? ? ? ? paint.setColor(ContextCompat.getColor(context, R.color.red));
? ? ? ? canvas.drawRoundRect(upRect, SizeUtils.dp2px(5), SizeUtils.dp2px(5), paint);
? ? ? ? if (movex == getWidth()) {
getParent().requestDisallowInterceptTouchEvent(false);
? ? ? ? ? canvas.drawBitmap(outBitmap, movex -bitmapWidth <0 ?
SizeUtils.dp2px(3) :movex - (bitmapWidth + SizeUtils.dp2px(3)),
SizeUtils.dp2px(3), paint);
? ? ? ? ? ? if (onSeekbarCompleListenner !=null) {
if (isNewdown) {
onSeekbarCompleListenner.comple();
? ? ? ? ? ? ? ? ? ? isNewdown =false;
? ? ? ? ? ? ? ? }
}
}else {
canvas.drawBitmap(inBitmap, movex -bitmapWidth <0 ? SizeUtils.dp2px(3) :movex -bitmapWidth, SizeUtils.dp2px(3), paint);
? ? ? ? ? ? if (onSeekbarCompleListenner !=null) {
onSeekbarCompleListenner.uncomple();
? ? ? ? ? ? }
}
}
private void initView() {
paint =new Paint();
? ? ? ? paint.setStyle(Paint.Style.FILL);
? ? ? ? paint.setColor(ContextCompat.getColor(context, R.color.red));
? ? ? ? paint.setStrokeWidth(2);
? ? ? ? bgRect =new RectF();
? ? ? ? upRect =new RectF();
? ? ? ? inBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.login_move);
? ? ? ? outBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.login_ok);
? ? ? ? bitmapWidth =inBitmap.getWidth();
? ? ? ? bitmapHeight =inBitmap.getHeight();
? ? }
@Override
? ? public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isNewdown =true;
? ? ? ? ? ? ? ? movex =bitmapWidth + SizeUtils.dp2px(3);
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
movex = (int) event.getX();
? ? ? ? ? ? ? ? invalidate();
break;
? ? ? ? ? ? case MotionEvent.ACTION_UP:
if (movex < getWidth()) {
movex =0;
? ? ? ? ? ? ? ? }
invalidate();
break;
? ? ? ? ? ? default:
break;
? ? ? ? }
return true;
? ? }
public void setOnSeekbarCompleListenner(OnSeekbarCompleListenner onSeekbarCompleListenner) {
this.onSeekbarCompleListenner = onSeekbarCompleListenner;
? ? }
public interface OnSeekbarCompleListenner {
void comple();
? ? ? ? void uncomple();
? ? }
}
```
里面用到的工具類:
```
public final class SizeUtils {
private SizeUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
? ? }
/**
* Value of dp to value of px.
*
? ?? * @param dpValue The value of dp.
? ?? * @return value of px
*/
? ? public static int dp2px(final float dpValue) {
final float scale = Resources.getSystem().getDisplayMetrics().density;
? ? ? ? return (int) (dpValue * scale +0.5f);
? ? }
/**
* Value of px to value of dp.
*
? ?? * @param pxValue The value of px.
? ?? * @return value of dp
*/
? ? public static int px2dp(final float pxValue) {
final float scale = Resources.getSystem().getDisplayMetrics().density;
? ? ? ? return (int) (pxValue / scale +0.5f);
? ? }
/**
* Value of sp to value of px.
*
? ?? * @param spValue The value of sp.
? ?? * @return value of px
*/
? ? public static int sp2px(final float spValue) {
final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity;
? ? ? ? return (int) (spValue * fontScale +0.5f);
? ? }
/**
* Value of px to value of sp.
*
? ?? * @param pxValue The value of px.
? ?? * @return value of sp
*/
? ? public static int px2sp(final float pxValue) {
final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity;
? ? ? ? return (int) (pxValue / fontScale +0.5f);
? ? }
/**
* Converts an unpacked complex data value holding a dimension to its final floating
? ?? * point value. The two parameters <var>unit</var> and <var>value
? ?? * are as in {@link TypedValue#TYPE_DIMENSION}.
*
? ?? * @param value The value to apply the unit to.
? ?? * @param unit? The unit to convert from.
? ?? * @return The complex floating point value multiplied by the appropriate
* metrics depending on its unit.
*/
? ? public static float applyDimension(final float value, final int unit) {
DisplayMetrics metrics = Utils.getApp().getResources().getDisplayMetrics();
? ? ? ? switch (unit) {
case TypedValue.COMPLEX_UNIT_PX:
return value;
? ? ? ? ? ? case TypedValue.COMPLEX_UNIT_DIP:
return value * metrics.density;
? ? ? ? ? ? case TypedValue.COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
? ? ? ? ? ? case TypedValue.COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f /72);
? ? ? ? ? ? case TypedValue.COMPLEX_UNIT_IN:
return value * metrics.xdpi;
? ? ? ? ? ? case TypedValue.COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f /25.4f);
? ? ? ? }
return 0;
? ? }
/**
* Force get the size of view.
? ?? * <p>e.g.
? ?? *
? ?? * SizeUtils.forceGetViewSize(view, new SizeUtils.onGetSizeListener() {
*? ?? Override
*? ?? public void onGetSize(final View view) {
*? ? ? ?? view.getWidth();
*? ?? }
* });
? ?? *
? ?? *
? ?? * @param view? ?? The view.
? ?? * @param listener The get size listener.
*/
? ? public static void forceGetViewSize(final View view, final onGetSizeListener listener) {
view.post(new Runnable() {
@Override
? ? ? ? ? ? public void run() {
if (listener !=null) {
listener.onGetSize(view);
? ? ? ? ? ? ? ? }
}
});
? ? }
/**
* Return the width of view.
*
? ?? * @param view The view.
? ?? * @return the width of view
*/
? ? public static int getMeasuredWidth(final View view) {
return measureView(view)[0];
? ? }
/**
* Return the height of view.
*
? ?? * @param view The view.
? ?? * @return the height of view
*/
? ? public static int getMeasuredHeight(final View view) {
return measureView(view)[1];
? ? }
/**
* Measure the view.
*
? ?? * @param view The view.
? ?? * @return arr[0]: view's width, arr[1]: view's height
*/
? ? public static int[]measureView(final View view) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
? ? ? ? if (lp ==null) {
lp =new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
? ? ? ? ? ? ? ? ? ? ViewGroup.LayoutParams.WRAP_CONTENT
? ? ? ? ? ? );
? ? ? ? }
int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
? ? ? ? int lpHeight = lp.height;
? ? ? ? int heightSpec;
? ? ? ? if (lpHeight >0) {
heightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight, View.MeasureSpec.EXACTLY);
? ? ? ? }else {
heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
? ? ? ? }
view.measure(widthSpec, heightSpec);
? ? ? ? return new int[]{view.getMeasuredWidth(), view.getMeasuredHeight()};
? ? }
///////////////////////////////////////////////////////////////////////////
// interface
///////////////////////////////////////////////////////////////////////////
? ? public interface onGetSizeListener {
void onGetSize(View view);
? ? }
}
```
這就是整個(gè)的代碼啦,代碼不多,有需要的直接拷過去用就行了,替換一下圖片,顏色,也可以做一下優(yōu)化。