要使用九宫格设置密码,先用自定义一个九宫格样式,使用的自定义的view画出九个点,然后重写onMeasure和onDraw,这两个方法,并处理onTouchEvent,这个事件
在Android视图的绘制和布局过程中,onMeasure和onDraw这两个方法的调用顺序是固定的。以下是它们通常的调用顺序:
onMeasure:
当一个视图被添加到布局容器中,或者其布局参数发生变化时,系统会首先调用视图的onMeasure方法。
onMeasure方法的目的是确定视图应该占据的空间大小,即视图的测量宽度和高度。
视图根据自身的内容、布局参数、以及来自父布局的测量规格(MeasureSpec)来决定自己的最佳大小。
一旦确定了测量大小,视图会通过调用setMeasuredDimension方法来设置其测量宽度和高度。
onLayout:
在所有子视图的onMeasure方法被调用并返回之后,父布局会调用其onLayout方法。
onLayout方法的目的是确定每个子视图在父布局中的精确位置。
父布局会根据子视图的测量大小和布局参数,以及自身的布局算法,来计算每个子视图的位置。
父布局会调用每个子视图的layout方法来设置其位置和大小。
onDraw:
在onLayout方法完成之后,如果视图需要绘制内容(即它不是一个透明的或者空的视图),那么它的onDraw方法会被调用。
onDraw方法的目的是在视图的画布上绘制内容。
在onDraw方法中,视图可以使用Canvas对象来绘制形状、文本、图片等。
通常,自定义视图会重写onDraw方法来提供自定义的绘制逻辑。
简而言之,onMeasure首先被调用以确定视图的大小,接着是onLayout来确定视图在父布局中的位置,最后是onDraw来在视图的画布上绘制内容。这个流程是Android视图绘制和布局的核心机制。
当在Android开发中处理View的onTouchEvent事件时,可以通过重写onTouchEvent方法来定义视图如何响应触摸事件。
public NinePointLineView(Context context) {
super(context);
cxt = context;
initPaint();
}
protected void onDraw(Canvas canvas) {
//画九点
drawNinePoint(canvas);
super.onDraw(canvas);
}
public class NinePointLineView extends View {
Paint linePaint = new Paint();
Paint whiteLinePaint = new Paint();
Paint textPaint = new Paint();
Bitmap defaultBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.lock);
int defaultBitmapRadius = defaultBitmap.getWidth() / 2;
Bitmap selectedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.indicator_lock_area);
int selectedBitmapDiameter = selectedBitmap.getWidth();
int selectedBitmapRadius = selectedBitmapDiameter / 2;
PointInfo[] points = new PointInfo[9];
PointInfo startPoint = null;
int width, height;
int moveX, moveY;
boolean isUp = false;
Context cxt;
StringBuffer lockString = new StringBuffer();
public NinePointLineView(Context context) {
super(context);
cxt = context;
// this.setBackgroundColor(Color.WHITE);//设置整个背景
initPaint();
}
public NinePointLineView(Context context, AttributeSet attrs) {
super(context, attrs);
// this.setBackgroundColor(Color.WHITE);//设置整个九宫格的背景
initPaint();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 解析测量规格中的模式和大小
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// 根据需要计算视图的宽度和高度
if (widthMode == MeasureSpec.EXACTLY) {
// 如果宽度是精确值,则使用它
width = widthSize;
} else {
// 否则,根据内容计算宽度
width = 400;
}
Log.e("NinePointLine", " heightMode="+heightMode );
width = widthSize > 600 ? widthSize : 600;
height = heightSize > 600 ? heightSize : 600;//限制最小区域防止出错
Log.e("NinePointLine", "onMeasure: Line 53 and width="+width+" and height="+height );
if (width != 0 && height != 0) {
initPoints(points);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
private int startX = 0, startY = 0;
@Override
protected void onDraw(Canvas canvas) {
//canvas.drawText("passwd:" + lockString, 0, 40, textPaint);
if (moveX != 0 && moveY != 0 && startX != 0 && startY != 0) {
drawLine(canvas, startX, startY, moveX, moveY);
}
drawNinePoint(canvas);
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean flag = true;
if (isUp) {
finishDraw();
flag = false;
} else {
handlingEvent(event);
flag = true;
}
return flag;
}
private void handlingEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
moveX = (int) event.getX();
moveY = (int) event.getY();
for (PointInfo temp : points) {
if (temp.isInMyPlace(moveX, moveY) && temp.isSelected() == false) {
temp.setSelected(true);
startX = temp.getCenterX();
startY = temp.getCenterY();
int len = lockString.length();
if (len != 0) {
int preId = lockString.charAt(len - 1) - 48;
points[preId].setNextId(temp.getId());
}
lockString.append(temp.getId());
break;
}
}
invalidate(0, height - width, width, height);
break;
case MotionEvent.ACTION_DOWN:
int downX = (int) event.getX();
int downY = (int) event.getY();
for (PointInfo temp : points) {
if (temp.isInMyPlace(downX, downY)) {
temp.setSelected(true);
startPoint = temp;
startX = temp.getCenterX();
startY = temp.getCenterY();
lockString.append(temp.getId());
break;
}
}
invalidate(0, height - width, width, height);
break;
case MotionEvent.ACTION_UP:
startX = startY = moveX = moveY = 0;
isUp = true;
invalidate();
savePwd();
break;
default:
break;
}
}
private void finishDraw() {
for (PointInfo temp : points) {
temp.setSelected(false);
temp.setNextId(temp.getId());
}
lockString.delete(0, lockString.length());
isUp = false;
invalidate();
}
private void initPoints(PointInfo[] points) {
int len = points.length;
int seletedSpacing = (width - selectedBitmapDiameter * 3) / 4;
int seletedX = seletedSpacing;
int seletedY = height - width + seletedSpacing;
int defaultX = seletedX + selectedBitmapRadius - defaultBitmapRadius;
int defaultY = seletedY + selectedBitmapRadius - defaultBitmapRadius;
for (int i = 0; i < len; i++) {
if (i == 3 || i == 6) {
seletedX = seletedSpacing;
seletedY += selectedBitmapDiameter + seletedSpacing;
defaultX = seletedX + selectedBitmapRadius
- defaultBitmapRadius;
defaultY += selectedBitmapDiameter + seletedSpacing;
}
points[i] = new PointInfo(i, defaultX, defaultY, seletedX, seletedY);
seletedX += selectedBitmapDiameter + seletedSpacing;
defaultX += selectedBitmapDiameter + seletedSpacing;
}
}
private void initPaint() {
Log.e("NinePointLine", "initPaint: 161" );
initLinePaint(linePaint);
initTextPaint(textPaint);
initWhiteLinePaint(whiteLinePaint);
}
/**
* @param paint
*/
private void initTextPaint(Paint paint) {
textPaint.setTextSize(30);
textPaint.setAntiAlias(true);
textPaint.setTypeface(Typeface.MONOSPACE);
}
/**
* @param paint
*/
private void initLinePaint(Paint paint) {
Log.e("NinePointLine", "initLinePaint: 178" );
paint.setColor(Color.GRAY);
paint.setStrokeWidth(30);//设置两个点之间的线的的宽度
paint.setAntiAlias(true);
paint.setStrokeCap(Cap.ROUND);
}
/**
* @param paint
*/
private void initWhiteLinePaint(Paint paint) {
paint.setColor(Color.WHITE);
paint.setStrokeWidth(20);//设置两个点之间的线的宽度
paint.setAntiAlias(true);
paint.setStrokeCap(Cap.ROUND);
}
/**
*
* @param canvas
*/
private void drawNinePoint(Canvas canvas) {
if (startPoint != null) {
drawEachLine(canvas, startPoint);
}
for (PointInfo pointInfo : points) {
if (pointInfo != null) {
if (pointInfo.isSelected()) {
canvas.drawBitmap(selectedBitmap, pointInfo.getSeletedX(),
pointInfo.getSeletedY(), null);
}
canvas.drawBitmap(defaultBitmap, pointInfo.getDefaultX(),
pointInfo.getDefaultY(), null);
}
}
}
/**
* @param canvas
* @param point
*/
private void drawEachLine(Canvas canvas, PointInfo point) {
if (point.hasNextId()) {
int n = point.getNextId();
drawLine(canvas, point.getCenterX(), point.getCenterY(),
points[n].getCenterX(), points[n].getCenterY());
drawEachLine(canvas, points[n]);
}
}
/**
*
* @param canvas
* @param startX
* @param startY
* @param stopX
* @param stopY
*/
private void drawLine(Canvas canvas, float startX, float startY,float stopX, float stopY) {
canvas.drawLine(startX, startY, stopX, stopY, linePaint);
canvas.drawLine(startX, startY, stopX, stopY, whiteLinePaint);
}
/**
* @author zkwlx
*
*/
private class PointInfo {
private int id;
private int nextId;
private boolean selected;
private int defaultX;
private int defaultY;
private int seletedX;
private int seletedY;
public PointInfo(int id, int defaultX, int defaultY, int seletedX,
int seletedY) {
this.id = id;
this.nextId = id;
this.defaultX = defaultX;
this.defaultY = defaultY;
this.seletedX = seletedX;
this.seletedY = seletedY;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public int getId() {
return id;
}
public int getDefaultX() {
return defaultX;
}
public int getDefaultY() {
return defaultY;
}
public int getSeletedX() {
return seletedX;
}
public int getSeletedY() {
return seletedY;
}
public int getCenterX() {
return seletedX + selectedBitmapRadius;
}
public int getCenterY() {
return seletedY + selectedBitmapRadius;
}
public boolean hasNextId() {
return nextId != id;
}
public int getNextId() {
return nextId;
}
public void setNextId(int nextId) {
this.nextId = nextId;
}
/**
* @param x
* @param y
*/
public boolean isInMyPlace(int x, int y) {
boolean inX = x > seletedX
&& x < (seletedX + selectedBitmapDiameter);
boolean inY = y > seletedY
&& y < (seletedY + selectedBitmapDiameter);
return (inX && inY);
}
}
public String getPwd() {//获取本次的密码
return lockString.toString();
}
/**
* 作用:保存密码并且判断界面的跳转
* */
public void savePwd(){
Intent intent = new Intent();
SharedPreferences shareDate = cxt.getSharedPreferences("GUE_PWD", MODE_PRIVATE);
boolean isSetFirst = shareDate.getBoolean("IS_SET_FIRST", false);
if(isSetFirst){//如果第一次已经设置密码,验证第二次和第一次是否一致
String pwd = this.getPwd();
String first_pwd = shareDate.getString("FIRST_PWD", "NO HAVE PWD");
if(pwd.equals(first_pwd)){//第二次密码和第一次密码一样 设置成功
shareDate.edit().clear().commit();
shareDate.edit().putBoolean("IS_SET", true).commit();
shareDate.edit().putString("GUE_PWD", pwd).commit();
intent.setClass(cxt, SetPwdResActivity.class);
}else{//第二次输入的密码和第一次输入的密码不一致
shareDate.edit().putBoolean("SECOND_ERROR", true).commit();
intent.setClass(cxt, MainActivity.class);
}
}else{//第一次设置手势密码
shareDate.edit().clear().commit();
shareDate.edit().putString("FIRST_PWD", this.getPwd()).commit();
shareDate.edit().putBoolean("IS_SET_FIRST", true).commit();
intent.setClass(cxt, MainActivity.class);
}
cxt.startActivity(intent);
((Activity)cxt).finish();
}
}