尝试自己动手写了一个简单的手势锁控件。多有不足,请帮忙更正。
自定义了一个GestureLockView,继承view类。
第一步:绘制。
大部分手势锁控件,主要包含3部分的绘制,圆点,外圈及路径。
首先让我们来绘制圆点,先计算出圆心位置
float x = gap * i + paddingLeft + largeRadius; float y = gap * j + paddingTop + largeRadius;
其中gap为圆心之间的间距,paddingleft为左边留出来的空白,paddingTop为控件上部留出来的空白,largeRadius为外圈大圆的半径。目前paddingleft与paddingtop为写死的固定值,gap则是在onmeasure方法中计算出来的。
gap = (getMeasuredWidth() - paddingLeft * 2 - largeRadius * 2) / (circleNum - 1);
在确定圆心坐标之后,我们可以开始圆及外圈的绘制了。
//绘制圆点 canvas.drawCircle(x, y, smallRadius, paint); //绘制圆 if (targetList.contains(i+j*circleNum)){ canvas.drawCircle(x,y,largeRadius,ringPaint); }
targetList里面存放被选择的圆点的标记,如果该圆点被选择了,则绘制相应的外圈圆。最后开始绘制路径。
//绘制path canvas.drawPath(mpath, pathPaint);
再绘制工作完成之后,就可以开始事件的处理了。
第二步:事件处理。
因为是继承view类,所以只需要重写onTouchEvent()方法就可以了。
首先在ACTION_DOWN事件里面,我们判断触摸位置是否在目标区域内(外圈圆内)。如果在目标区域内才响应后续事件,否则不响应后续事件。
/** * 判断触点是否在目标范围类 * @param x * @param y * @return */ private boolean isTarget(float x,float y){ for (int i = 0; i < circleNum; i++) { for (int j = 0; j < circleNum; j++) { float deltX = gap * i + paddingLeft + largeRadius; float deltY = gap * j + paddingTop + largeRadius; if(Math.pow(deltX-x,2)+ Math.pow(deltY-y,2)<=Math.pow(largeRadius,2)){ addPoint(i+j*circleNum,deltX,deltY); return true; } } } return false; }
在目标区域内,将圆心坐标添加到mpath对象中,并将位置标记记录下。
//添加连接点 private void addPoint(int i,float x,float y){ //将path起点移动到目标位置 if(targetList.isEmpty()){ mpath.moveTo(x,y); } //不存在则添加 if(!targetList.contains(i)) { targetList.add(i); mpath.lineTo(x, y); invalidate(); } }
mpath中没有元素时,相当于是第一个点的,所以要将mpath的起点位置移动到该位置。
在ACTION_MOVE事件中,判断是否经过目标区域,如果在目标区域,只需要添加点就行了,所以可以直接调用isTarget()方法就可以了。
最后在ACTION_UP事件中验证密码,并清空mpath与targetList。
if(validPwd()){ mpath.reset(); targetList.clear(); invalidate(); //todo 验证成功之后的动作 Toast.makeText(this.getContext(), "pwd is correct", Toast.LENGTH_SHORT).show(); }else { if(!targetList.isEmpty()) { pathPaint.setColor(Color.RED); invalidate(); //密码错误 Toast.makeText(this.getContext(), "password is incorrect", Toast.LENGTH_SHORT).show(); //1秒后清除path this.postDelayed(mrun,1000); } };
Runnable mrun=new Runnable() { @Override public void run() { pathPaint.setColor(Color.parseColor("#B3B3B3")); mpath.reset(); targetList.clear(); invalidate(); } };
源码具体参见https://github.com/krystenia/GestureLockView