-
效果,就跟手机上的九点手势解锁一样,上个图吧:
过程嘛感觉确实没啥好讲的了,涉及的知识以前的博客都说过了,无非就是canva,paint,touch事件这些,画画圆圈画画线条,剩下的就是细节处理逻辑了。都在代码里,所以这里就主要是贴资源吧。
这个自定义view就一个类,源码如下:
布局(view的宽高你可以随意指定,bg1是效果里那张背景图片):123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295packagecom.cc.library.view;importandroid.content.Context;importandroid.graphics.Canvas;importandroid.graphics.Color;importandroid.graphics.Paint;importandroid.graphics.Path;importandroid.location.Location;importandroid.util.AttributeSet;importandroid.util.Log;importandroid.view.MotionEvent;importandroid.view.View;importandroid.view.ViewTreeObserver;/*** 图案解锁view* Created by zhangyu on 2016-07-15 15:05.*/publicclassUnlockViewextendsView {privatestaticfinalString TAG ="UnlockView";//view宽高privatefloatwidth, height;//平均宽高(分三份)privatefloataverageWidth, averageHeight;//九个点的位置数据,从左到右、从上到下 123...789Location[] locations =newLocation[9];//圆圈半径privatefloatradius;//绘制密码privateint[] drawingPwd =newint[9];//正确的密码privateint[] rightPwd;//画笔privatePaint whitePaint, cyanPaint;//已经绘制过了的点个数privateintdrawedNumber;//当前正被触摸的点privateLocation nowTouchedPosition =newLocation();//监听privateUnlockListener unlockListener;publicvoidsetUnlockListener(UnlockListener unlockListener) {this.unlockListener = unlockListener;}publicUnlockView(Context context) {super(context);init();}publicUnlockView(Context context, AttributeSet attrs) {super(context, attrs);init();}publicUnlockView(Context context, AttributeSet attrs,intdefStyleAttr) {super(context, attrs, defStyleAttr);init();}privatevoidinit() {ViewTreeObserver vto = getViewTreeObserver();vto.addOnGlobalLayoutListener(newViewTreeObserver.OnGlobalLayoutListener() {@OverridepublicvoidonGlobalLayout() {height = getHeight();width = getWidth();Log.d(TAG,"width = "+ width +" ,height = "+ height);averageWidth = width / 3f;averageHeight = height / 3f;radius = averageHeight > averageWidth ? averageWidth / 5f : averageHeight / 5f;initLocation();invalidate();}});whitePaint =newPaint();whitePaint.setAntiAlias(true);whitePaint.setColor(Color.parseColor("#ffffff"));whitePaint.setStyle(Paint.Style.STROKE);cyanPaint =newPaint();cyanPaint.setAntiAlias(true);cyanPaint.setColor(Color.parseColor("#4169E1"));cyanPaint.setStyle(Paint.Style.STROKE);initDrawingPwd();}privatevoiddrawStart() {drawedNumber =0;}privatevoiddrawOver() {//debugStringBuffer sb =newStringBuffer();for(inti =0; i < drawingPwd.length; i++) {sb.append(drawingPwd[i] +",");}Log.i(TAG,"drawingPwd:"+ sb.toString());initLocation();initDrawingPwd();drawedNumber =0;invalidate();}/*** 初始化绘制密码*/privatevoidinitDrawingPwd() {for(inti =0; i <9; i++) {drawingPwd[i] = -1;}}/*** 初始化九个点坐标*/privatevoidinitLocation() {for(inti =0; i <9; i++) {locations[i] =newLocation();locations[i].deawed =false;//纵向1、2、3列x坐标if(i %3==0) {locations[i].x = averageWidth *0.5f;}elseif(i %3==1) {locations[i].x = averageWidth *1.5f;}elseif(i %3==2) {locations[i].x = averageWidth *2.5f;}//横向1、2、3排y坐标if(i /3==0) {locations[i].y = averageHeight *0.5f;}elseif(i /3==1) {locations[i].y = averageHeight *1.5f;}elseif(i /3==2) {locations[i].y = averageHeight *2.5f;}}}@OverrideprotectedvoidonDraw(Canvas canvas) {for(inti =0; i <9; i++) {if(!locations[i].deawed) {//没被画whitePaint.setStrokeWidth(4);canvas.drawPoint(locations[i].x, locations[i].y, whitePaint);whitePaint.setStrokeWidth(1.5f);canvas.drawCircle(locations[i].x, locations[i].y, radius, whitePaint);}else{//被画过了cyanPaint.setStrokeWidth(8);canvas.drawPoint(locations[i].x, locations[i].y, cyanPaint);cyanPaint.setStrokeWidth(3f);canvas.drawCircle(locations[i].x, locations[i].y, radius, cyanPaint);}intlastestDrawedPoint = -1;if(drawedNumber >0)lastestDrawedPoint = drawingPwd[drawedNumber -1];if(lastestDrawedPoint != -1) {Location lastestDrawedLocation = locations[lastestDrawedPoint];//最新一个被选中的点cyanPaint.setStrokeWidth(3f);canvas.drawLine(lastestDrawedLocation.x, lastestDrawedLocation.y, nowTouchedPosition.x, nowTouchedPosition.y, cyanPaint);}if(drawedNumber >1) {for(intj =0; j < drawedNumber -1; j++) {cyanPaint.setStrokeWidth(3f);canvas.drawLine(locations[drawingPwd[j]].x, locations[drawingPwd[j]].y, locations[drawingPwd[j +1]].x, locations[drawingPwd[j +1]].y, cyanPaint);}}}super.onDraw(canvas);}floatmoveX, moveY;@OverridepublicbooleanonTouchEvent(MotionEvent event) {switch(event.getAction()) {caseMotionEvent.ACTION_DOWN:drawStart();break;caseMotionEvent.ACTION_MOVE:moveX = event.getX();moveY = event.getY();dealPosition(moveX, moveY);break;caseMotionEvent.ACTION_UP:if(unlockListener !=null) {unlockListener.drawOver(drawingPwd);if(verificationPwd(rightPwd)) {unlockListener.isPwdRight(true);}else{unlockListener.isPwdRight(false);}}drawOver();break;}returntrue;}privatevoiddealPosition(floatnowX,floatnowY) {nowTouchedPosition.x = nowX;nowTouchedPosition.y = nowY;intnowTouched = getWhichOneBeTouched(nowX, nowY);if(nowTouched != -1) {//触摸到了点上if(!locations[nowTouched].deawed) {//如果这点没被触摸过drawingPwd[drawedNumber] = nowTouched;//记录密码drawedNumber++;//被触摸点数+1Log.v(TAG,"nowTouched "+ nowTouched +" ,drawedNumber = "+ drawedNumber);}locations[nowTouched].deawed =true;}invalidate();}privateclassLocation {publicfloatx = -1, y = -1;publicbooleandeawed;//是否被画过了}/*** 获取被触摸到的点** @param x 坐标x点* @param y 坐标y点* @return 被触摸的坐标点位置 或者-1*/privateintgetWhichOneBeTouched(floatx,floaty) {for(inti =0; i < locations.length; i++) {doublelPowX = Math.pow(Math.abs(x - locations[i].x),2);doublelPowY = Math.pow(Math.abs(y - locations[i].y),2);if(Math.sqrt(lPowX + lPowY) < radius)returni;}return-1;}/*** 校验密码是否正确** @param rightPwd 正确的密码* @return 正确返回true 否则返回false*/publicbooleanverificationPwd(int[] rightPwd) {if(rightPwd ==null)returnfalse;for(inti =0; i < rightPwd.length; i++) {if(rightPwd[i] != drawingPwd[i])returnfalse;}returntrue;}/*** 获取当前绘制的密码** @return*/publicint[] getDrawedPwd() {returndrawingPwd;}/*** 设置正确的密码** @param rightPwd*/publicvoidsetRightPwd(int[] rightPwd) {this.rightPwd = rightPwd;}//监听接口publicinterfaceUnlockListener {publicvoiddrawOver(int[] pwd);publicvoidisPwdRight(booleanisRight);}}12345<!--?xml version="1.0"encoding="utf-8"?--><relativelayout android:background="@drawable/bg1"android:layout_height="match_parent"android:layout_width="match_parent"xmlns:android="http://schemas.android.com/apk/res/android"><com.cc.library.view.unlockview android:id="@+id/unlock_view"android:layout_alignparentbottom="true"android:layout_height="360dp"android:layout_width="match_parent"></com.cc.library.view.unlockview></relativelayout>
使用:1234567891011121314151617181920212223242526272829303132333435363738394041packagecom.sz.china.testmoudule;importandroid.app.Activity;importandroid.os.Bundle;importandroid.widget.Toast;importcom.cc.library.view.UnlockView;/*** Created by zhangyu on 2016-07-15 14:55.*/publicclassTestUnlockViewActivityextendsActivity {privateUnlockView unlockView;@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.unlock_activity);unlockView = (UnlockView) findViewById(R.id.unlock_view);//设置回调监听unlockView.setUnlockListener(newUnlockView.UnlockListener() {@OverridepublicvoiddrawOver(int[] pwd) {//绘制完成,获取绘制的密码unlockView.getDrawedPwd();}@OverridepublicvoidisPwdRight(booleanisRight) {//密码是否校验正确if(isRight)Toast.makeText(TestUnlockViewActivity.this,"密码正确",Toast.LENGTH_SHORT).show();elseToast.makeText(TestUnlockViewActivity.this,"密码错误",Toast.LENGTH_SHORT).show();}});int[] pwd = {0,5,7,6};unlockView.setRightPwd(pwd);//设置密码}}
相关文章: