Android 自定义手势键盘

自定义手势键盘

手势键盘有三种状态,初始状态、点击状态和错误状态,分别以下列三个图片显示。
在这里插入图片描述在这里插入图片描述在这里插入图片描述

2. 数据类CircleArea

CircleArea类用来记录手势键盘的信息。

static class CircleArea {
    float x, y; // 圆心X
    float radius; // 圆半径
    int mValue; // 值

    public CircleArea(float x, float y, float radius, int value) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.mValue = value;
    }

    public CircleArea moveTo(float dx, float dy, int value) {
        return new CircleArea(x + dx, y + dy, radius, value);
    }

    // 该点是否在圆内
    public boolean contain(float x, float y) {
        return Math.sqrt(Math.pow(this.x - x, 2) + Math.pow(this.y - y, 2)) < radius;
    }

    public int getValue() {
        return mValue;
    }

}

3. 手势键盘GestureView

初始化,在构造函数里面初始化图片和画笔,在onMeasure(int, int)计算手势点的位置。

public class GestureView extends View {
    private static final int INVALID_COUNT = 4;

    enum Status {
        Normal,
        Error
    }

    private Bitmap mNormalBmp, mClickBmp, mErrorBmp;
    private int mNormalColor, mErrorColor;
    private Paint mBitmapPaint, mLinePaint;

    private List<CircleArea> mTotalCircles = new ArrayList<>();
    private List<CircleArea> mLinkCircle = new ArrayList<>();

    private PointF mCurrentPoint = null;
    private Status mStatus = Status.Normal;

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

    public GestureView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        mNormalBmp = BitmapFactory.decodeResource(getResources(), R.drawable.gesture_circle_normal);
        mClickBmp = BitmapFactory.decodeResource(getResources(), R.drawable.gesture_circle_click);
        mErrorBmp = BitmapFactory.decodeResource(getResources(), R.drawable.gesture_circle_error);

        mNormalColor = getResources().getColor(R.color.gesture_normal_line);
        mErrorColor = getResources().getColor(R.color.gesture_error_line);

        mBitmapPaint = new Paint();
        mBitmapPaint.setFilterBitmap(true);

        mLinePaint = new Paint();
        mLinePaint.setStrokeWidth(10);
        mLinePaint.setAntiAlias(true);
    }

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

        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();

        int squareWidth = Math.min(measuredWidth, measuredHeight);
        // 界面被3等分,每个手势占1/6
        float radius = squareWidth / 12.0f;
        float startX = (measuredWidth - squareWidth) / 2.0f;
         float startY = (measuredHeight - squareWidth) / 2.0f;

        mTotalCircles.clear();
        CircleArea circleArea = new CircleArea(startX + radius*2, startY + radius*2, radius, 1);
        mTotalCircles.add(circleArea);
        mTotalCircles.add(circleArea.moveTo(radius*4, 0, 2));
        mTotalCircles.add(circleArea.moveTo(radius*8, 0, 3));

        mTotalCircles.add(circleArea.moveTo(0, radius*4, 4));
        mTotalCircles.add(circleArea.moveTo(radius*4, radius*4, 5));
        mTotalCircles.add(circleArea.moveTo(radius*8, radius*4, 6));

        mTotalCircles.add(circleArea.moveTo(0, radius*8, 7));
        mTotalCircles.add(circleArea.moveTo(radius*4, radius*8, 8));
        mTotalCircles.add(circleArea.moveTo(radius*8, radius*8, 9));

        int width = (int)(radius * 2);
        mNormalBmp = Bitmap.createScaledBitmap(mNormalBmp, width, width, false);
        mClickBmp = Bitmap.createScaledBitmap(mClickBmp, width, width, false);
        mErrorBmp = Bitmap.createScaledBitmap(mErrorBmp, width, width, false);
    }

}

onTouchEvent(MotionEvent)方法捕捉手势

@Override
public boolean onTouchEvent(MotionEvent event) {
    // 只有在正常状态下,触摸才生效
    if (mStatus == Status.Normal) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                // 记录手势
                moveTo(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                moveTo(event.getX(), event.getY());

                // 如果小于有效数量
                if (mLinkCircle.size() < INVALID_COUNT) {
                    Toast.makeText(getContext(), "InvalidCount " + mLinkCircle.size(),
                        Toast.LENGTH_LONG).show();
                    // 错误状态,界面不可点
                    mStatus = Status.Error;
                    // 2秒后清空
                    postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            clearCircle();
                            postInvalidate();
                        }
                    }, 2000);
                } else {
                    Toast.makeText(getContext(), "Success " + getLinkText(),
                            Toast.LENGTH_LONG).show();
                    clearCircle();
                }
                break;
        }
        postInvalidate();
    }
    return true;
}

private void moveTo(float x, float y) {
    // 当前触摸点
    mCurrentPoint = new PointF(x, y);

    // 如果不在选择列表中,加入选择列表
    for (CircleArea circle : mTotalCircles) {
        if (circle.contain(x, y) && !mLinkCircle.contains(circle)) {
            if (!mLinkCircle.contains(circle)) {
                mLinkCircle.add(circle);
            }
            return;
        }
    }
}

private String getLinkText() {
    String text = "";
    for(CircleArea circle : mLinkCircle) {
        text += circle.getValue();
    }
    return text;
}

private void clearCircle() {
    mLinkCircle.clear();
    mCurrentPoint = null;
    mStatus = Status.Normal;
}

onDraw(Canvas)方法绘制手势

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

    canvas.drawColor(getResources().getColor(R.color.black));
    // 如果选择列表不为空
    if (mLinkCircle.size() > 0) {
        // 设置连接线的颜色
        if (mStatus == Status.Normal) {
            mLinePaint.setColor(mNormalColor);
        } else {
            mLinePaint.setColor(mErrorColor);
        }
        // 手势键盘之间的连接线
        CircleArea lastCircle = mLinkCircle.get(0);
        for (int i = 1; i < mLinkCircle.size(); i++) {
            CircleArea circle = mLinkCircle.get(i);
            canvas.drawLine(lastCircle.x, lastCircle.y, circle.x, circle.y, mLinePaint);
            lastCircle = circle;
        }
        // 手势键盘和当前点之间的连接线
        if (mCurrentPoint != null && mStatus == Status.Normal) {
            canvas.drawLine(lastCircle.x, lastCircle.y, mCurrentPoint.x, mCurrentPoint.y, mLinePaint);
        }
    }

    for (CircleArea circle : mTotalCircles) {
        drawCircle(canvas, circle);
    }
}

private void drawCircle(Canvas canvas, CircleArea circle) {
    Bitmap circleBitmap = mNormalBmp;
    if (mLinkCircle.contains(circle)) {
        if (mStatus == Status.Normal) {
            circleBitmap = mClickBmp;
        } else {
            circleBitmap = mErrorBmp;
        }
    }
    // 不同状态下绘制不同的图片。
    canvas.drawBitmap(circleBitmap, circle.x - circle.radius, circle.y -     circle.radius, mBitmapPaint);
}

4. 效果如下

在这里插入图片描述 在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值