转载请注明出处: http://blog.csdn.net/forwardyzk/article/details/42676213
现在的手机都有屏幕锁,有图案的,有数字的。下面介绍一个使用图案的屏幕锁。
思路:
1.根据屏幕的宽度,计算出9个点的坐标和半径。
2.使用画笔画出9个圆。
3.根据触摸的坐标判断是否在圆的范围之内,如果在圆的范围之内,表示此圆被触摸了。
4.根绝触摸圆的顺序,根据圆心,构建滑动的path,然后使用画笔画出。
计算圆的圆心和半径
int perSize = 0; if (cycles == null && (perSize = getWidth() / 6) > 0) { cycles = new MyCycle[9]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { MyCycle cycle = new MyCycle(); 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; } } }
根绝控件的宽度,将控件的宽度分为6部分,圆心在1,3,5的线上。
如图:
初始化画笔
paintNormal = new Paint(); paintNormal.setAntiAlias(true); paintNormal.setStrokeWidth(3); paintNormal.setStyle(Paint.Style.STROKE);
setAntiAlias(true):设置线的边缘平滑
setStrokeWidth():设置线宽
setStyle()设置样式Paint.Style.STROKE ,Paint.Style.FILL,Paint.Style.FILL_STROKE
在onTouchEvevt()对触摸事件进行处理
public boolean onTouchEvent(MotionEvent event) { if (canContinue) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: { 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; if (linedCycles.size() >= minCountCycle) {// 大于等于连接圆的最小个数 // 检查结果 StringBuffer sb = new StringBuffer(); for (int i = 0; i < linedCycles.size(); i++) { sb.append(linedCycles.get(i)); } result = key.equals(sb.toString()); if (onGestureFinishListener != null) { onGestureFinishListener.OnGestureFinish(result); } } else { Toast.makeText(getContext(), "最少连接" + minCountCycle + "个圆", 0).show(); } 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(); } }, 1000); break; } } invalidate(); } return true; }
MotionEvent.ACTION_DOWN和MotionEvent.ACTION_MOVE中根据按下和移动的坐标,判断是在那一个圆形图形范围内,如在其范围内,那么就添加到一个保存触摸的圆的集合中。为了计算其滑动的线路和判断线路是否正确。在添加之前,要保证集合中没有此圆,否则线路就会重复。
MotionEvent.ACTION_UP:在手指离开的时候,根绝存放触摸圆的集合,计算其触摸的顺序(形成的图形)是否正确,是根绝圆对象的代表的数字做判断。当手指离开时,把计算结果通过接口传递出去。
public class MyCycle { private int ox; // 圆心横坐标 private int oy; // 圆心纵坐标 private float r; // 半径长度 private Integer num; // 代表数值 private boolean onTouch; // false=未选中 public int getOx() { return ox; } public void setOx(int ox) { this.ox = ox; } public int getOy() { return oy; } public void setOy(int oy) { this.oy = oy; } public float getR() { return r; } public void setR(float r) { this.r = r; } public Integer getNum() { return num; } public void setNum(Integer num) { this.num = num; } public boolean isOnTouch() { return onTouch; } public void setOnTouch(boolean onTouch) { this.onTouch = onTouch; } public boolean isPointIn(int x, int y) { double distance = Math.sqrt((x - ox) * (x - ox) + (y - oy) * (y - oy)); return distance < r; }
判断是否在其范围内是亮点之间的距离是否小于半径来做判断。
要记得最后离开的后,延迟清除触摸的图形。
在onDraw方法中,根绝触摸的顺序,触摸的状态随时更改图形的颜色。
protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < cycles.length; i++) { if (!canContinue && !result) { paintOnTouch.setColor(ERROR_COLOR); paintInnerCycle.setColor(ERROR_COLOR); paintLines.setColor(ERROR_COLOR); } else if (cycles[i].isOnTouch()) { paintOnTouch.setColor(OUT_CYCLE_ONTOUCH); paintInnerCycle.setColor(INNER_CYCLE_ONTOUCH); paintLines.setColor(LINE_COLOR); } else { paintNormal.setColor(OUT_CYCLE_NORMAL); paintInnerCycle.setColor(INNER_CYCLE_ONTOUCH); paintLines.setColor(LINE_COLOR); } if (cycles[i].isOnTouch()) { if (!isShowPattern) { canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR(), paintNormal); } else { canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR(), paintOnTouch); drawInnerBlueCycle(cycles[i], canvas); } } else { canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR(), paintNormal); } } drawLine(canvas); }
有四中画笔,paintNormal:正常显示的使用的画笔,paintOnTouch:触摸后的外圆使用的画笔,paintInnerCycle:触摸后的内圆使用的画笔,paintLines:连线使用的画笔。
根绝当前的状态,设置画笔的的颜色,颜色如下
对应五种颜色
private int OUT_CYCLE_NORMAL = Color.rgb(108, 119, 138); // 正常外圆颜色 private int OUT_CYCLE_ONTOUCH = Color.rgb(025, 066, 103); // 选中外圆颜色 private int INNER_CYCLE_ONTOUCH = Color.rgb(002, 210, 255); // 选择内圆颜色 private int LINE_COLOR = Color.argb(127, 002, 210, 255); // 连接线颜色 private int ERROR_COLOR = Color.argb(127, 255, 000, 000); // 连接错误醒目提示颜色
画出触摸的线路
private void drawLine(Canvas canvas) { if (!isShowPattern) { return; } 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); } }
根绝触摸过的圆的圆心,按照顺序把圆心连接起啦,就构成了连接的线路。
使用的主要方法有:
setMinCountCycle(int minCountCycle):设置连接最小圆的个数,默认为1
setShowPattern(boolean isShowPath):是否显示连接的图案,默认显示
setOnGestureFinishListener(
OnGestureFinishListener onGestureFinishListener):设置结果返回值监听
setKey(String key):设置正确图案代表的值
==========================================
设置画笔的颜色和线宽,不设置有默认值
setErrorColor(int color):结果错误显示的颜色
setLinesPaint(float width, int color):设置连线的线宽和颜色
setNormalPaint(float width, int color):设置默认外圆展示的线宽和颜色
setOnTouchPaint(float width, int color):设置触摸外圆的线宽和颜色
setInnerCyclePaint(float width, int color):设置触摸内圆的线宽和颜色
使用步骤:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/start_background" tools:context=".MainActivity" > <com.example.view.GestureLockView android:id="@+id/gv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="#0000" /> </RelativeLayout>
MainActivity.java
public class MainActivity extends Activity { private GestureLockView gv; private SharedPreLockUtils spUtil; @Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); spUtil = SharedPreLockUtils.getInstance(getApplicationContext()); gv = (GestureLockView) findViewById(R.id.gv); gv.setKey("0124678"); // Z 字型 gv.setOnGestureFinishListener(new OnGestureFinishListener() { @Override public void OnGestureFinish(boolean success) { Toast.makeText(MainActivity.this, String.valueOf(success), Toast.LENGTH_SHORT).show(); if (success) { startSettingActivity(); } } }); gv.setShowPattern(spUtil.getIsShowPattern()); } public void startSettingActivity() { MainActivity.this.startActivity(new Intent(MainActivity.this, SettingActivity.class)); } @Override protected void onResume() { super.onResume(); gv.setShowPattern(spUtil.getIsShowPattern()); if (spUtil.getBoolean("ISCHANGE", false)) { gv.setNormalPaint( 3f, MainActivity.this.getResources().getColor( android.R.color.holo_red_light)); gv.setLinesPaint( 10f, MainActivity.this.getResources().getColor( android.R.color.holo_green_light)); gv.setInnerCyclePaint(25f, MainActivity.this.getResources() .getColor(android.R.color.darker_gray)); gv.setOnTouchPaint( 10f, MainActivity.this.getResources().getColor( android.R.color.holo_orange_dark)); gv.setErrorColor( MainActivity.this.getResources().getColor( android.R.color.holo_purple)); } } }
使用了滑动开关,其使用方法请参考自定义滑动开关
源码下载: http://download.csdn.net/detail/forwardyzk/8357367
效果图: