Android 自定义手势解锁控件

本文介绍如何在Android中自定义一个简单易用的手势解锁View。通过创建Circle类来表示圆点,并在GestureLockView中处理触摸事件,绘制连接路径。此组件可以用于实现个性化的解锁方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义了一个简单的手势解锁View,如下图所示。
仅仅供参考。


代码:
public class Circle {
    private int x;//x坐标
    private int y;//y坐标
    private int r;//半径
    private int num;
    private boolean isTouch;

    public Circle(int x, int y, int r, int num) {

        this.x = x;
        this.y = y;
        this.r = r;
        this.num = num;
    }


    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getR() {
        return r;
    }

    public void setR(int r) {
        this.r = r;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public boolean isTouch() {
        return isTouch;
    }

    public void setIsTouch(boolean isTouch) {
        this.isTouch = isTouch;
    }
}

public class GestureLockView extends View {

    Circle[] mCircles = new Circle[9];
    /**
     * 用来记录手指划过的结果 eg:"0124678"
     */
    private StringBuilder lineNumStr = new StringBuilder();

    int CIRCLE_R;// 圆环半径
    int SMALL_CIR_R = 12;//被选中圆环内部圆环半径
    static final int PADDING = 8;//边距
    static final int VIBRAT_TIME = 200;//震动时长
    static final int CHECK_TIME = 5000;//ACTION_UP后延时
    int mWidth;//View 宽
    int mHeight;//View 高
    Paint mCirclePaint;// 圆环画笔
    Paint mPathPaint;//线画笔

    Paint mSelectCirPaint;//内实心圆画笔

    Path mPath;//圆环 连线Path
    private int lineColor = Color.GREEN;
    private int circleColor = Color.GRAY;

    private int circleSelectColor = Color.GREEN;

    private Vibrator mVibrator;

    Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (mListener != null) {
                mListener.gestureResult(lineNumStr.toString());
                lineNumStr.delete(0, lineNumStr.length());
            }
            return true;
        }
    });

    public GestureLockView(Context context) {
        this(context, null);
    }

    public GestureLockView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {

        mCirclePaint = new Paint();
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setStrokeWidth(4f);
        mCirclePaint.setStyle(Paint.Style.STROKE);

        mPathPaint = new Paint();
        mPathPaint.setAntiAlias(true);
        mPathPaint.setStrokeWidth(4f);
        mPathPaint.setStyle(Paint.Style.STROKE);
        mPathPaint.setColor(lineColor);

        mSelectCirPaint = new Paint();
        mSelectCirPaint.setAntiAlias(true);
        mSelectCirPaint.setStyle(Paint.Style.FILL);
        mSelectCirPaint.setColor(circleSelectColor);

        mPath = new Path();
        lineNumStr.append("");

        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawPath(mPath, mPathPaint);

        for (int i = 0; i < mCircles.length; i++) {
            Circle circle = mCircles[i];
            if (circle.isTouch()) {
                mCirclePaint.setColor(circleSelectColor);
                canvas.drawCircle(circle.getX(), circle.getY(), circle.getR(), mCirclePaint);
                canvas.drawCircle(circle.getX(), circle.getY(), SMALL_CIR_R, mSelectCirPaint);
            } else {
                mCirclePaint.setColor(circleColor);
                canvas.drawCircle(circle.getX(), circle.getY(), circle.getR(), mCirclePaint);
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;

        CIRCLE_R = mWidth / 12;

        int firstX = CIRCLE_R + PADDING;
        int secondX = mWidth / 2;
        int thirdX = mWidth - CIRCLE_R - PADDING;

        int firstY = CIRCLE_R + PADDING;
        int secondY = mHeight / 2;
        int thirdY = mHeight - CIRCLE_R - PADDING;
        //初始化 9个圆环
        mCircles[0] = new Circle(firstX, firstY, CIRCLE_R, 0);
        mCircles[1] = new Circle(secondX, firstY, CIRCLE_R, 1);
        mCircles[2] = new Circle(thirdX, firstY, CIRCLE_R, 2);

        mCircles[3] = new Circle(firstX, secondY, CIRCLE_R, 3);
        mCircles[4] = new Circle(secondX, secondY, CIRCLE_R, 4);
        mCircles[5] = new Circle(thirdX, secondY, CIRCLE_R, 5);

        mCircles[6] = new Circle(firstX, thirdY, CIRCLE_R, 6);
        mCircles[7] = new Circle(secondX, thirdY, CIRCLE_R, 7);
        mCircles[8] = new Circle(thirdX, thirdY, CIRCLE_R, 8);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float touchX = event.getX();
        float touchY = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                checkPoint(touchX, touchY);
                break;
            case MotionEvent.ACTION_MOVE:
                checkPoint(touchX, touchY);
                break;
            case MotionEvent.ACTION_UP:
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        mPath.reset();
                        for (Circle mCircle : mCircles) {
                            mCircle.setIsTouch(false);
                        }
                        postInvalidate();
                        mHandler.sendEmptyMessage(0x11);

                    }
                }, CHECK_TIME);
                break;
        }
        invalidate();
        return true;
    }

    /**
     * 检查手指划过的点是否位于 未被选中的圆环中
     * 如果在则更改圆环touch属性、更新Path、更新选中结果
     *
     * @param touchX
     * @param touchY
     */
    private void checkPoint(float touchX, float touchY) {
        for (Circle circle : mCircles) {
            if (!circle.isTouch()) {
                if (Math.abs(touchX - circle.getX()) <= circle.getR()
                        && Math.abs(touchY - circle.getY()) <= circle.getR()) {
                    //说明选中的点在该Circle中
                    circle.setIsTouch(true);
                    mVibrator.vibrate(VIBRAT_TIME);
                    String line = lineNumStr.toString();
                    if (line.length() > 0) {
                        char c = line.charAt(line.length() - 1);
                        int index = Integer.parseInt(c + "");
                        mPath.quadTo(mCircles[index].getX(), mCircles[index].getY(),
                                circle.getX(), circle.getY());
                    } else {
                        mPath.moveTo(circle.getX(), circle.getY());
                    }
                    lineNumStr.append(circle.getNum());
                }
            }
        }
    }

    private LockListener mListener;
    
    public interface LockListener {
        void gestureResult(String result);
    }

    public void setListener(LockListener listener) {
        mListener = listener;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值