要使用九宫格设置密码,先用自定义一个九宫格样式,使用的自定义的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();}@Overrideprotected 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);}@Overrideprotected 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;@Overrideprotected 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);}@Overridepublic 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();}
}