自定义滑块验证View

来源:互联网 发布:php中文手册下载 编辑:程序博客网 时间:2024/06/05 18:02

最近项目上要把原先发送验证码的地方的图片验证改成滑块验证,于是重新自定义了一个View,先来看一下实现的效果图:

滑块验证

中间那个可以拖动的滑块就是一个自定义View,下面贴上它的实现代码:

package 马赛克.view;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import 马赛克;import 马赛克.CommonUtil;/** * Created by sjb on 2016/6/30. * 拖动验证的小滑块 */public class BlockVerifyView extends View {    /**     * 滑块起点的X坐标     */    private float mBlockStartX;    /**     * 滑块终点的X坐标     */    private float mBlockEndX;    /**     * 上一个X坐标     */    private float mLastX;    /**     * 画笔     */    private Paint mPaint;    private Paint mBgPaint;    private boolean isSuccess;    private OnVerifyListener listener;    public interface OnVerifyListener {        void success();        void fail();    }    public void setOnVerifyListener(OnVerifyListener onVerifyListener) {        this.listener = onVerifyListener;    }    public BlockVerifyView(Context context) {        super(context);        init();    }    public BlockVerifyView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public BlockVerifyView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    void init() {        mPaint = new Paint();        mPaint.setAntiAlias(true);        mBgPaint = new Paint();        mBgPaint.setAntiAlias(true);        mBgPaint.setColor(getResources().getColor(R.color.sa_light_g));        mBgPaint.setStyle(Paint.Style.STROKE);    }    private int getMeasure(int measure, int defaultSize) {        int result = 300;        int mode = MeasureSpec.getMode(measure);        int size = MeasureSpec.getSize(measure);        if (mode == MeasureSpec.EXACTLY) {            result = size;        } else if (mode == MeasureSpec.AT_MOST) {            result = Math.min(CommonUtil.dip2px(getContext(), defaultSize), size);        }        return result;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        setMeasuredDimension(getMeasure(widthMeasureSpec, 300), getMeasure(heightMeasureSpec, 40));    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        mBlockStartX = getWidth() * 0.05f;        mBlockEndX = mBlockStartX + getWidth() * 0.15f;    }    @Override    protected void onDraw(Canvas canvas) {        drawText(canvas);        drawLeftArea(canvas);        drawWhiteBlock(canvas);        drawThreeRec(canvas);        if (isSuccess) {            drawSuccess(canvas);        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                if (event.getX() > mBlockStartX && event.getX() < mBlockEndX) {                    mLastX = event.getX();                    return true;                }                break;            case MotionEvent.ACTION_MOVE:                if (event.getY() > 0 && event.getY() < getHeight()) {                    if ((mBlockStartX + event.getX() - mLastX) > getWidth() * 0.05f                            && (mBlockStartX + event.getX() - mLastX + getWidth() * 0.15f) < getWidth()) {                        mBlockStartX += event.getX() - mLastX;                        mBlockEndX = mBlockStartX + getWidth() * 0.15f;                        mLastX = event.getX();                        if (getWidth() - mBlockEndX < 10) {                            isSuccess = true;                        } else {                            isSuccess = false;                        }                        invalidate();                        return true;                    }                }                break;            case MotionEvent.ACTION_UP:                if (listener != null) {                    if (getWidth() - mBlockEndX < 10) {                        listener.success();                    } else {                        listener.fail();                    }                    return true;                }                break;            default:                break;        }        return super.onTouchEvent(event);    }    /**     * 绘制文字     *     * @param canvas     */    private void drawText(Canvas canvas) {        mPaint.setColor(getResources().getColor(R.color.sa_light_g));        mPaint.setTextAlign(Paint.Align.CENTER);        mPaint.setTextSize(CommonUtil.dip2px(getContext(), 12));        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();        int baseline = (getHeight() + 0 - fontMetrics.bottom - fontMetrics.top) / 2;        canvas.drawText("按住滑块拖至最右边", getWidth() * 0.5f, baseline, mPaint);    }    /**     * 绘制左侧已滑过的区域     */    private void drawLeftArea(Canvas canvas) {        mPaint.setColor(getResources().getColor(R.color.block_bg));        mPaint.setStyle(Paint.Style.FILL);        canvas.drawRect(0, 0, mBlockStartX, getHeight(), mPaint);    }    /**     * 绘制白色小滑块     */    private void drawWhiteBlock(Canvas canvas) {        mPaint.setColor(getResources().getColor(R.color.white));        mPaint.setStyle(Paint.Style.FILL);        canvas.drawRect(mBlockStartX, 0, mBlockEndX, getHeight(), mPaint);        canvas.drawRect(mBlockStartX - 2, 0, mBlockEndX + 2, getHeight(), mBgPaint);    }    /**     * 绘制滑块上的三条矩形区域     */    private void drawThreeRec(Canvas canvas) {        mPaint.setColor(getResources().getColor(R.color.block_bg));        mPaint.setStyle(Paint.Style.FILL);        float totalBlockX = mBlockEndX - mBlockStartX;        canvas.drawRect(mBlockStartX + totalBlockX * 0.25f, 10, mBlockStartX + totalBlockX * 0.30f, getHeight() - 10, mPaint);        canvas.drawRect(mBlockStartX + totalBlockX * 0.475f, 10, mBlockStartX + totalBlockX * 0.525f, getHeight() - 10, mPaint);        canvas.drawRect(mBlockStartX + totalBlockX * 0.7f, 10, mBlockStartX + totalBlockX * 0.75f, getHeight() - 10, mPaint);    }    /**     * 验证通过后绘制     * @param canvas     */    private void drawSuccess(Canvas canvas) {        mPaint.setColor(getResources().getColor(R.color.white));        mPaint.setStyle(Paint.Style.STROKE);        mPaint.setStrokeWidth(3);        Path path = new Path();        path.moveTo(getWidth() * 0.5f - 20, getHeight() * 0.5f - 10);        path.lineTo(getWidth() * 0.5f, getHeight() * 0.5f + 10);        path.lineTo(getWidth() * 0.5f + 20, getHeight() * 0.5f - 30);        canvas.drawPath(path, mPaint);    }}

代码不难,控制好坐标就可以了。

其中定义了一个接口OnVerifyListener ,供使用者进行验证通过和失败时的处理,每次手指离开时进行回调。

但是这个View用在这个有键盘弹出的界面还是出现了一点小插曲,下面的这段代码:

  @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        mBlockStartX = getWidth() * 0.05f;        mBlockEndX = mBlockStartX + getWidth() * 0.15f;    }

刚开始我是写在这里的:

 @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        mBlockStartX = getWidth() * 0.05f;        mBlockEndX = mBlockStartX + getWidth() * 0.15f;    }

用在这里发现每次键盘弹出或隐藏时,滑块都会回到初始位置,不能停留在上次的绘图状态,这下就尴尬了不是。

于是在这个View的各个方法中打印日志,发现每次键盘弹出或隐藏时,都回调了onLayout方法,难怪位置又被初始化了……

好的,那就改变策略,在onSizeChanged中初始化试试,结果只能是完美!

于是一个滑块验证就这样ko了~

欢迎吐槽、拍砖、卖萌……

0 0