设置手势密码,看大神弄的,我自己也跟着学了一遍,还是不太懂,但依然分享给大家
大家看代码吧!
1、mainactivity:
1 package com.wangy.wiperswitch; 2 3 import android.app.Instrumentation; 4 import android.content.Intent; 5 import android.content.SharedPreferences; 6 import android.support.v7.app.AppCompatActivity; 7 import android.os.Bundle; 8 import android.view.View; 9 import android.widget.Button;10 import android.widget.Toast;11 12 public class MainActivity extends AppCompatActivity implements View.OnClickListener {13 14 private Button btn_gesture;15 private String password;16 17 @Override18 protected void onCreate(Bundle savedInstanceState) {19 super.onCreate(savedInstanceState);20 setContentView(R.layout.activity_main);21 init();22 }23 private void init(){24 btn_gesture = (Button)findViewById(R.id.btn_gesture);25 btn_gesture.setOnClickListener(MainActivity.this);26 27 }28 29 @Override30 public void onClick(View v) {31 switch (v.getId()){32 case R.id.btn_gesture:{33 Intent intent=new Intent(MainActivity.this,GestureSetingActivity.class);34 startActivityForResult(intent,RESULT_OK);35 // finish();36 break;37 }38 }39 }40 41 @Override42 protected void onActivityResult(int requestCode, int resultCode, Intent data) {43 super.onActivityResult(requestCode, resultCode, data);44 if (requestCode==RESULT_OK){45 if (data!=null){46 Bundle bundle = data.getExtras();47 if (bundle!=null){48 Boolean isOk=bundle.getBoolean("isOk");49 if (isOk){50 password = bundle.getString("password");51 }else {52 Toast.makeText(MainActivity.this,"您两次输入的手势密码不相同,设置失败!",Toast.LENGTH_SHORT).show();53 }54 }55 }56 }57 }58 }
mainactivi布局:
1 26 11 12 23 2421 22
2点击进入设置密码界面GestureSetingActivity
1 package com.wangy.wiperswitch; 2 3 import android.content.Context; 4 import android.content.Intent; 5 import android.gesture.Gesture; 6 import android.graphics.Bitmap; 7 import android.graphics.BitmapFactory; 8 import android.graphics.Canvas; 9 import android.graphics.Matrix;10 import android.graphics.Paint;11 import android.os.Bundle;12 import android.os.PersistableBundle;13 import android.support.v4.app.Fragment;14 import android.support.v7.app.AppCompatActivity;15 import android.util.AttributeSet;16 import android.view.Display;17 import android.view.MotionEvent;18 import android.view.View;19 import android.view.WindowManager;20 import android.widget.FrameLayout;21 import android.widget.Toast;22 23 import com.wangy.wiperswitch.Custom.Drawl;24 import com.wangy.wiperswitch.Custom.GestureView;25 import com.wangy.wiperswitch.R;26 import com.wangy.wiperswitch.utils.SharepreferenceUtil;27 28 /**29 * Created by xhb on 2016/9/13.30 */31 public class GestureSetingActivity extends AppCompatActivity {32 33 private FrameLayout boby_layout;34 private String pass;35 private GestureView content;36 private int time=0;37 38 @Override39 protected void onCreate(Bundle savedInstanceState) {40 super.onCreate(savedInstanceState);41 setContentView(R.layout.gesture_setting_layout);42 init();43 }44 protected void init(){45 pass = "";46 boby_layout = (FrameLayout)findViewById(R.id.body_layout);47 WindowManager m = getWindowManager();48 Display d = m.getDefaultDisplay();49 content = new GestureView(this, pass, d.getWidth(), new Drawl.GestureCallBack() {50 @Override51 public void checkedSuccess(String s) {52 if (s.length()<3){53 Toast.makeText(GestureSetingActivity.this,"手势密码最少是3个!",Toast.LENGTH_SHORT).show();54 }else {55 if (time==0){56 Toast.makeText(GestureSetingActivity.this,"请再输入一次!",Toast.LENGTH_SHORT).show();57 time++;58 pass=s;//将第一次输入的密码与第二次输入的密码比较是否一致59 }else {60 if (pass.equals(s)){61 Toast.makeText(GestureSetingActivity.this,"设置成功!手势密码为:"+s,Toast.LENGTH_SHORT).show();62 Bundle bundle = new Bundle();63 bundle.putBoolean("isOk",true);64 bundle.putString("password", s);65 Intent intent = new Intent();66 intent.putExtras(bundle);67 setResult(RESULT_OK, intent);68 SharepreferenceUtil.setstring(GestureSetingActivity.this,"pass",s);69 finish();70 }else {71 Bundle bundle = new Bundle();72 bundle.putBoolean("isOk", false);73 Intent intent = new Intent();74 intent.putExtras(bundle);75 setResult(RESULT_OK, intent);76 finish();77 }78 }79 }80 }81 82 @Override83 public void checkedFail() {84 Toast.makeText(GestureSetingActivity.this,"校验失败!",Toast.LENGTH_SHORT).show();85 }86 });87 88 //设置手势解锁显示到哪个布局里面89 content.setParentView(boby_layout);90 }91 }
GestureSetingActivity布局
1 26 7 14 15
3、2中设计到了一个非常重要的自定义控件GestureView,这是手势密码特别重要的view,接下来看代码吧!
1 package com.wangy.wiperswitch.Custom; 2 3 import android.content.Context; 4 import android.view.View; 5 import android.view.ViewGroup; 6 import android.widget.ImageView; 7 8 import com.wangy.wiperswitch.R; 9 import com.wangy.wiperswitch.utils.ScreenUtils; 10 11 import java.util.ArrayList; 12 import java.util.List; 13 14 /** 15 * Created by xhb on 2016/9/14. 16 */ 17 public class GestureView extends ViewGroup{ 18 19 private int baseNum = 6; 20 21 private int[] screenDispaly; 22 23 private int d; 24 /** 25 * 声明一个集合用来封装坐标集合 26 */ 27 private Listlist; 28 private Context context; 29 private Drawl drawl; 30 31 /** 32 * 包含9个ImageView的容器,初始化 33 * @param context 34 * @param passWord 用户传入密码 35 * @param callBack 手势绘制完毕的回调 36 */ 37 public GestureView(Context context, String passWord, float width, Drawl.GestureCallBack callBack) { 38 super(context); 39 screenDispaly = ScreenUtils.getScreenDispaly(context); 40 d = screenDispaly[0]/3; 41 this.list = new ArrayList (); 42 this.context = context; 43 // 添加9个图标 44 addChild(); 45 // 初始化一个可以画线的view 46 drawl = new Drawl(context, list,passWord,width,callBack); 47 } 48 49 private void addChild(){ 50 for (int i = 0; i < 9; i++) { 51 ImageView image = new ImageView(context); 52 image.setBackgroundResource(R.drawable.lock_pattern_node_normal); 53 this.addView(image); 54 55 // 第几行 56 int row = i / 3; 57 // 第几列 58 int col = i % 3; 59 60 // 定义点的每个属性 61 int leftX = col*d+d/baseNum; 62 int topY = row*d+d/baseNum; 63 int rightX = col*d+d-d/baseNum; 64 int bottomY = row*d+d-d/baseNum; 65 66 Point p = new Point(leftX, rightX, topY, bottomY, image,i+1); 67 68 this.list.add(p); 69 } 70 } 71 72 73 public void setParentView(ViewGroup parent){ 74 // 得到屏幕的宽度 75 int width = screenDispaly[0]; 76 LayoutParams layoutParams = new LayoutParams(width, width); 77 78 this.setLayoutParams(layoutParams); 79 drawl.setLayoutParams(layoutParams); 80 81 parent.addView(drawl); 82 parent.addView(this); 83 84 } 85 86 87 @Override 88 protected void onLayout(boolean changed, int l, int t, int r, int b) { 89 for (int i = 0; i < getChildCount(); i++) { 90 //第几行 91 int row = i/3; 92 //第几列 93 int col = i%3; 94 View v = getChildAt(i); 95 v.layout(col*d+d/baseNum, row*d+d/baseNum+50, col*d+d-d/baseNum, row*d+d-d/baseNum+50); 96 } 97 } 98 99 @Override100 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {101 super.onMeasure(widthMeasureSpec, heightMeasureSpec);102 for (int i = 0; i < getChildCount(); i++) {103 View v = getChildAt(i);104 v.measure(widthMeasureSpec, heightMeasureSpec);105 }106 }107 108 }
这里面也有个非常重要的Drawl(用来初始化一个可以画线的view),还有自定义笔Point
Drawl:
1 package com.wangy.wiperswitch.Custom; 2 3 /** 4 * Created by xhb on 2016/9/14. 5 */ 6 7 import android.content.Context; 8 import android.graphics.Bitmap; 9 import android.graphics.Canvas; 10 import android.graphics.Color; 11 import android.graphics.Paint; 12 import android.graphics.PorterDuff; 13 import android.util.Pair; 14 import android.view.MotionEvent; 15 import android.view.View; 16 17 import java.util.ArrayList; 18 import java.util.List; 19 20 import android.content.Context; 21 import android.graphics.Bitmap; 22 import android.graphics.Canvas; 23 import android.graphics.Color; 24 import android.graphics.Paint; 25 import android.graphics.Paint.Style; 26 import android.graphics.PorterDuff; 27 import android.util.Pair; 28 import android.view.MotionEvent; 29 import android.view.View; 30 31 import com.wangy.wiperswitch.utils.StringUtils; 32 33 import java.util.ArrayList; 34 import java.util.List; 35 36 37 /** 38 * 39 * @author wangy 40 * 41 */ 42 public class Drawl extends View { 43 private int mov_x;// 声明起点坐标 44 private int mov_y; 45 private Paint paint;// 声明画笔 46 private Canvas canvas;// 画布 47 private Bitmap bitmap;// 位图 48 49 private Listlist;// 装有各个view坐标的集合 50 private List > lineList;// 记录画过的线 51 52 /** 53 * 手指当前在哪个Point内 54 */ 55 private Point currentPoint; 56 /** 57 * 用户绘图的回调 58 */ 59 private GestureCallBack callBack; 60 61 /** 62 * 用户当前绘制的图形密码 63 */ 64 private StringBuilder passWordSb; 65 66 /** 67 * 用户传入的passWord 68 */ 69 private String passWord; 70 71 public Drawl(Context context, List list, String passWord, float width, GestureCallBack callBack) { 72 super(context); 73 paint = new Paint(Paint.DITHER_FLAG);// 创建一个画笔 74 bitmap = Bitmap.createBitmap((int)width, 800, Bitmap.Config.ARGB_8888); // 设置位图的宽高 75 canvas = new Canvas(); 76 canvas.setBitmap(bitmap); 77 78 paint.setStyle(Paint.Style.STROKE);// 设置非填充 79 paint.setStrokeWidth(10);// 笔宽5像素 80 paint.setColor(Color.parseColor("#ffffff"));// 设置颜色 81 paint.setAntiAlias(true);// 不显示锯齿 82 83 this.list = list; 84 this.lineList = new ArrayList >(); 85 this.callBack = callBack; 86 87 //初始化密码缓存 88 this.passWordSb = new StringBuilder(); 89 this.passWord = passWord; 90 } 91 92 // 画位图 93 @Override 94 protected void onDraw(Canvas canvas) { 95 // super.onDraw(canvas); 96 canvas.drawBitmap(bitmap, 0, 0, null); 97 } 98 99 // 触摸事件100 @Override101 public boolean onTouchEvent(MotionEvent event) {102 switch (event.getAction()) {103 case MotionEvent.ACTION_DOWN:104 105 mov_x = (int) event.getX();106 mov_y = (int) event.getY();107 108 // 判断当前点击的位置是处于哪个点之内109 currentPoint = getPointAt(mov_x, mov_y);110 if (currentPoint != null) {111 currentPoint.setHighLighted(true);112 passWordSb.append(currentPoint.getNum());113 }114 // canvas.drawPoint(mov_x, mov_y, paint);// 画点115 invalidate();116 break;117 case MotionEvent.ACTION_MOVE:118 clearScreenAndDrawList();119 120 // 得到当前移动位置是处于哪个点内121 Point pointAt = getPointAt((int) event.getX(), (int) event.getY());122 //代表当前用户手指处于点与点之前123 if(currentPoint==null && pointAt == null){124 return true;125 }else{ //代表用户的手指移动到了点上126 if(currentPoint == null){ //先判断当前的point是不是为null127 //如果为空,那么把手指移动到的点赋值给currentPoint128 currentPoint = pointAt;129 //把currentPoint这个点设置选中为true;130 currentPoint.setHighLighted(true);131 passWordSb.append(currentPoint.getNum());132 }133 }134 135 if (pointAt == null || currentPoint.equals(pointAt)136 || pointAt.isHighLighted()) {137 // 点击移动区域不在圆的区域 或者138 // 如果当前点击的点与当前移动到的点的位置相同139 // 那么以当前的点中心为起点,以手指移动位置为终点画线140 canvas.drawLine(currentPoint.getCenterX(),141 currentPoint.getCenterY()+50, event.getX(), event.getY()+50,142 paint);// 画线143 } else {144 // 如果当前点击的点与当前移动到的点的位置不同145 // 那么以前前点的中心为起点,以手移动到的点的位置画线146 canvas.drawLine(currentPoint.getCenterX(),147 currentPoint.getCenterY()+50, pointAt.getCenterX(),148 pointAt.getCenterY()+50, paint);// 画线149 150 pointAt.setHighLighted(true);151 152 Pair pair = new Pair (currentPoint,153 pointAt);154 lineList.add(pair);155 156 // 赋值当前的point;157 currentPoint = pointAt;158 passWordSb.append(currentPoint.getNum());159 }160 invalidate();161 break;162 case MotionEvent.ACTION_UP:// 当手指抬起的时候163 // 清掉屏幕上所有的线,只画上集合里面保存的线164 if(StringUtils.isEmpty(passWord)){165 callBack.checkedSuccess(passWordSb.toString());166 }else{167 if(passWord.equals(passWordSb.toString())){168 //代表用户绘制的密码手势与传入的密码相同169 callBack.checkedSuccess(passWordSb.toString());170 }else{171 //用户绘制的密码与传入的密码不同。172 callBack.checkedFail();173 }174 }175 176 //重置passWordSb177 passWordSb = new StringBuilder();178 //清空保存点的集合179 lineList.clear();180 //重新绘制界面181 clearScreenAndDrawList();182 for (Point p : list) {183 p.setHighLighted(false);184 }185 invalidate();186 break;187 default:188 break;189 }190 return true;191 }192 193 /**194 * 通过点的位置去集合里面查找这个点是包含在哪个Point里面的195 *196 * @param x197 * @param y198 * @return 如果没有找到,则返回null,代表用户当前移动的地方属于点与点之间199 */200 private Point getPointAt(int x, int y) {201 202 for (Point point : list) {203 // 先判断x204 int leftX = point.getLeftX();205 int rightX = point.getRightX();206 if (!(x >= leftX && x < rightX)) {207 // 如果为假,则跳到下一个对比208 continue;209 }210 211 int topY = point.getTopY();212 int bottomY = point.getBottomY();213 if (!(y >= topY && y < bottomY)) {214 // 如果为假,则跳到下一个对比215 continue;216 }217 218 // 如果执行到这,那么说明当前点击的点的位置在遍历到点的位置这个地方219 return point;220 }221 222 return null;223 }224 225 /**226 * 清掉屏幕上所有的线,然后画出集合里面的线227 */228 private void clearScreenAndDrawList() {229 canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);230 for (Pair pair : lineList) {231 canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY()+50,232 pair.second.getCenterX(), pair.second.getCenterY()+50, paint);// 画线233 }234 }235 236 public interface GestureCallBack{237 238 /**239 * 代表用户绘制的密码与传入的密码相同240 */241 void checkedSuccess(String s);242 /**243 * 代表用户绘制的密码与传入的密码不相同244 */245 void checkedFail();246 }247 248 }
Point:
1 package com.wangy.wiperswitch.Custom; 2 3 import android.widget.ImageView; 4 5 import com.wangy.wiperswitch.R; 6 7 /** 8 * Created by xhb on 2016/9/14. 9 */ 10 public class Point { 11 /** 12 * 左边x的值 13 */ 14 private int leftX; 15 /** 16 * 右边x的值 17 */ 18 private int rightX; 19 /** 20 * 上边y的值 21 */ 22 private int topY; 23 /** 24 * 下边y的值 25 */ 26 private int bottomY; 27 /** 28 * 这个点对应的ImageView控件 29 */ 30 private ImageView image; 31 32 /** 33 * 中心x值 34 */ 35 private int centerX; 36 37 /** 38 * 中心y值 39 */ 40 private int centerY; 41 42 /** 43 * 是否是高亮(划过) 44 */ 45 private boolean highLighted; 46 47 /** 48 * 代表这个Point对象代表的数字,从1开始(直接感觉从1开始) 49 */ 50 private int num; 51 52 public Point(int leftX, int rightX, int topY, int bottomY, ImageView image, int num) { 53 super(); 54 this.leftX = leftX; 55 this.rightX = rightX; 56 this.topY = topY; 57 this.bottomY = bottomY; 58 this.image = image; 59 60 this.centerX = (leftX + rightX) / 2; 61 this.centerY = (topY + bottomY) / 2; 62 63 this.num = num; 64 } 65 66 public int getLeftX() { 67 return leftX; 68 } 69 70 public void setLeftX(int leftX) { 71 this.leftX = leftX; 72 } 73 74 public int getRightX() { 75 return rightX; 76 } 77 78 public void setRightX(int rightX) { 79 this.rightX = rightX; 80 } 81 82 public int getTopY() { 83 return topY; 84 } 85 86 public void setTopY(int topY) { 87 this.topY = topY; 88 } 89 90 public int getBottomY() { 91 return bottomY; 92 } 93 94 public void setBottomY(int bottomY) { 95 this.bottomY = bottomY; 96 } 97 98 public ImageView getImage() { 99 return image;100 }101 102 public void setImage(ImageView image) {103 this.image = image;104 }105 106 public int getCenterX() {107 return centerX;108 }109 110 public void setCenterX(int centerX) {111 this.centerX = centerX;112 }113 114 public int getCenterY() {115 return centerY;116 }117 118 public void setCenterY(int centerY) {119 this.centerY = centerY;120 }121 122 public boolean isHighLighted() {123 return highLighted;124 }125 126 public void setHighLighted(boolean highLighted) {127 this.highLighted = highLighted;128 if (highLighted) {129 this.image.setBackgroundResource(R.drawable.lock_pattern_node_pressed);130 } else {131 this.image.setBackgroundResource(R.drawable.lock_pattern_node_normal);132 }133 }134 135 public int getNum() {136 return num;137 }138 139 public void setNum(int num) {140 this.num = num;141 }142 143 @Override144 public int hashCode() {145 final int prime = 31;146 int result = 1;147 result = prime * result + bottomY;148 result = prime * result + ((image == null) ? 0 : image.hashCode());149 result = prime * result + leftX;150 result = prime * result + rightX;151 result = prime * result + topY;152 return result;153 }154 155 @Override156 public boolean equals(Object obj) {157 if (this == obj)158 return true;159 if (obj == null)160 return false;161 if (getClass() != obj.getClass())162 return false;163 Point other = (Point) obj;164 if (bottomY != other.bottomY)165 return false;166 if (image == null) {167 if (other.image != null)168 return false;169 } else if (!image.equals(other.image))170 return false;171 if (leftX != other.leftX)172 return false;173 if (rightX != other.rightX)174 return false;175 return topY == other.topY;176 }177 178 @Override179 public String toString() {180 return "Point [leftX=" + leftX + ", rightX=" + rightX + ", topY="181 + topY + ", bottomY=" + bottomY + "]";182 }183 }
4、这就完成了,不过其中需要用到一些工具类我都奉上啦!
ScreenUtils:获取手机屏幕的高度和宽度
1 public class ScreenUtils { 2 @SuppressWarnings("deprecation") 3 public static int[] getScreenDispaly(Context context){ 4 WindowManager wm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE); 5 int width=wm.getDefaultDisplay().getWidth();//手机屏幕的宽度 6 int height=wm.getDefaultDisplay().getHeight();//手机屏幕的高度 7 int result[] = {width,height}; 8 return result; 9 10 }11 }
SharepreferenceUtil:本地记录密码,一般用于登录
1 package com.wangy.wiperswitch.utils; 2 3 import android.content.Context; 4 import android.content.SharedPreferences; 5 6 /** 7 * Created by xhb on 2016/9/18. 8 */ 9 public class SharepreferenceUtil {10 private static final String name="cogi";11 public static boolean getboolean(Context con,String key,boolean defaultValues){12 SharedPreferences sp=con.getSharedPreferences(name13 ,Context.MODE_PRIVATE);14 return sp.getBoolean(key, defaultValues);15 }16 17 public static void putboolean(Context con,String key,boolean values){18 SharedPreferences sp=con.getSharedPreferences(name,Context.MODE_PRIVATE);19 sp.edit().putBoolean(key, values).commit();20 }21 22 public static String getstring(Context con,String key,String defaultValues){23 SharedPreferences sp=con.getSharedPreferences(name24 ,Context.MODE_PRIVATE);25 return sp.getString(key, defaultValues);26 }27 28 public static void setstring(Context con,String key,String values){29 SharedPreferences sp=con.getSharedPreferences(name,Context.MODE_PRIVATE);30 sp.edit().putString(key, values).commit();31 }32 }
StringUtils:字符串常用的
1 public class StringUtils { 2 public StringUtils() { 3 } 4 5 public static boolean isEmpty(String str) { 6 return str == null || str.length() == 0; 7 } 8 9 public static boolean equals(String str1, String str2) {10 return str1 == null?str2 == null:str1.equals(str2);11 }12 13 public static boolean equalsIgnoreCase(String str1, String str2) {14 return str1 == null?str2 == null:str1.equalsIgnoreCase(str2);15 }16 17 public static boolean gbk(String str) {18 int count = 0;19 String regEx = "[\\u4e00-\\u9fa5]";20 Pattern p = Pattern.compile(regEx);21 Matcher m = p.matcher(str);22 23 while(m.find()) {24 for(int i = 0; i <= m.groupCount(); ++i) {25 ++count;26 }27 }28 29 if(count > 0) {30 return true;31 } else {32 return false;33 }34 }35
图片也打包送上了背景图就不放了,随大家了
看看效果图吧!