基本思路,继承一个view,重写其ondraw方法,在其中9个圆(也可以自己自定义属性,让使用者控制圆的个数,但是过多或者过少都会影响美观而且太复杂的话用户不容易记住自己设置的手势,所以基本可以不用考虑自定义这个属性),每个圆都有一个相当于下标的属性,用于唯一确定一个圆,最后手势的比较也是通过这个坐标点,也就是说你画的手势它只记录了下标值(比如你的手势是一个z,它记录下来的是下标的位置顺序(0124678),你同样画一个z,当时是逆向画(8764210)就没有用,因为最后比较的是下标的顺序),千万不要以为它比较的是图形,画好圆之后就可以重写view的ontouchEvent事件,根据点击的坐标记录被点击的圆,在ondraw中根据是否被点击变换图形颜色,同时画出path,以上就是基本的实现原理,接下来看看代码:
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); int perSize = 0; if (cycles == null && (perSize = getWidth() / 6) > 0) { cycles = new MyCircle[9]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { MyCircle cycle = new MyCircle(); cycle.setNum(i * 3 + j); cycle.setOx(perSize * (j * 2 + 1)); cycle.setOy(perSize * (i * 2 + 1)); cycle.setR(perSize * 0.5f); cycles[i * 3 + j] = cycle; } } } }
@Override public boolean onTouchEvent(MotionEvent event) { if (canContinue) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: onGestureFinishListener.OnGestureStart(); case MotionEvent.ACTION_MOVE: canContinue = true; /** * event.getX()是相对于view的坐标点,getrawx是相对于屏幕的 */ eventX = (int) event.getX(); eventY = (int) event.getY(); for (int i = 0; i < cycles.length; i++) { if (cycles[i].isPointIn(eventX, eventY)) { cycles[i].setOnTouch(true); if (!linedCycles.contains(cycles[i].getNum())) { linedCycles.add(cycles[i].getNum()); } } } break; case MotionEvent.ACTION_UP: canContinue = false; StringBuffer sb = new StringBuffer(); for (int i = 0; i < linedCycles.size(); i++) { sb.append(linedCycles.get(i)); } if (onGestureFinishListener != null) { result = onGestureFinishListener.OnGestureFinish(sb .toString()); } timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { // 还原 eventX = eventY = 0; for (int i = 0; i < cycles.length; i++) { cycles[i].setOnTouch(false); } linedCycles.clear(); linePath.reset(); canContinue = true; postInvalidate(); timer.cancel(); } }, 1000); break; default: break; } invalidate(); } return true; }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < cycles.length; i++) { if(!result){ /** * 手指已经抬起,并且手势错误 */ paintOutCycle.setColor(ERROR_COLOR); paintInnerCycle.setColor(INNER_CYCLE_ERROR_COLOR); paintLines.setColor(ERROR_COLOR); } if (cycles[i].isOnTouch()) { /** * 圆圈被选中 */ paintOutCycle.setColor(OUT_CYCLE_ONTOUCH); paintInnerCycle.setColor(INNER_CYCLE_TOUCHED); paintLines.setColor(LINE_COLOR); } else { paintOutCycle.setColor(OUT_CYCLE_NORMAL); paintInnerCycle.setColor(INNER_CYCLE_NOTOUCH); paintLines.setColor(LINE_COLOR); } canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR(), paintOutCycle); canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR() / 1.5f, paintInnerCycle); } drawLine(canvas); } private void drawLine(Canvas canvas) { linePath.reset(); if (linedCycles.size() > 0) { for (int i = 0; i < linedCycles.size(); i++) { int index = linedCycles.get(i); float x = cycles[index].getOx(); float y = cycles[index].getOy(); if (i == 0) { linePath.moveTo(x,y); } else { linePath.lineTo(x,y); } } if(canContinue){ linePath.lineTo(eventX,eventY); }else{ linePath.lineTo(cycles[linedCycles.get(linedCycles.size()-1)].getOx(), cycles[linedCycles.get(linedCycles.size()-1)].getOy()); } canvas.drawPath(linePath, paintLines); } }
参考:http://blog.csdn.net/centralperk/article/details/23374683
我整理之后的代码,主要简化了一些代码:http://download.csdn.net/detail/u012806692/9456989