转载请注明出处: 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
效果图: