android 屏幕 密码错误 判断,Android滑动解锁加强版

先看效果图:

3595cf43e925

效果图.gif

1.加入背景图,以及滑动解锁的点

(1) 背景图由于只有一张,所以我们选择用xml文件配置

android:id="@+id/iv_bg"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:src="@drawable/bg"

android:scaleType="center"/>

此部分特别简单,不做过多赘述

(2)加入点,我们需要插入很多个点,xml文件可以配置,但是重复代码太多,造成代码臃肿,所以我们选用代码加入

private void initNineDot(int res,int visiable,boolean record) {

rl = findViewById(R.id.rl_root);//这是我们需要加入的父视图

padding = pixelFromDp(40);//像素值的转换

//计算两点中心点之间的距离

Point p = new Point();

getWindowManager().getDefaultDisplay().getSize(p);

//获取图片

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.normal);

float space = (p.x - 2 * padding - bitmap.getWidth()) / 2;

//计算起始点的坐标

float x = padding;

float y = p.y / 2 - space - bitmap.getHeight();

if (!record) {

for (int i = 0; i < 3; i++) {

for (int j = 0; j < 3; j++) {

creatDot(res, (int) (y + space * i), (int) (x + space * j), visiable,0);

}

}

}else{

int index=1;

for (int i = 0; i < 3; i++) {

for (int j = 0; j < 3; j++) {

creatDot(res, (int) (y + space * i), (int) (x + space * j), visiable,index);

index++;

}

}

}

}

getWindowManager().getDefaultDisplay().getSize(p):获取当前屏幕的尺寸

record:布尔类型,用来判断是否需要在该点加入tag值,加入tag值是为了为方便我们在滑动的过程中记录划过的点,以便于把密码记下来

下面是加入点的关键代码:

rivate void creatDot(int res,int top,int left,int visiable,int index){

ImageView selected=new ImageView(this);

selected.setBackgroundResource(res);

selected.setTag(index);

RelativeLayout.LayoutParams parmas=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

parmas.leftMargin= left;

parmas.topMargin= top;

selected.setVisibility(visiable);

rl.addView(selected,parmas);

//判断res是否是selected 则要加入ImageView数组中

if(res==R.drawable.selected){

dotViews.add(selected);

}

}

ImageView.addView()方法中需传递两个参数,一个子控件,一个是位置参数;

接下里关于onTouch方法来获取密码的我们创建一个新的类

先贴上MainActivity类中的onCreat()方法:

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

dotViews=new ArrayList<>();

setContentView(R.layout.activity_main);

//初始化9个正常点

initNineDot(R.drawable.normal, View.VISIBLE,false);

initDrawView();

//初始化9个高光点

initNineDot(R.drawable.selected,View.INVISIBLE,true);

//将所以点的数组 转递给DrawView

dv.setDotViews(dotViews);

TextView textView=findViewById(R.id.tv_alertText);

dv.setAlerttextView(textView);

}

2.DrawView类

3595cf43e925

image.png

我们需要在该类中接收我们在MainActivity中加入的ImageView视图,我们采取的方法是:在DrawView中加入set,get方法,在MainActivity中进行调用,完成参数的传递

DrawView类中的set方法

3595cf43e925

image.png

MainActivity中对应的使用方法:

3595cf43e925

image.png

3.画板的加入:

我们不仅限于旨在两点之间加线,如:

3595cf43e925

image.png

我们需要当手指滑动到某个位置是,线就画到某个位置,所以我们加入了画板

要画画的话,我们少不了画笔:

private void init(){

paint=new Paint(Paint.ANTI_ALIAS_FLAG);

paint.setColor(Color.YELLOW);

paint.setStrokeWidth(10);

paint.setStyle(Paint.Style.STROKE);

}

初始化好了之后,我们就可以着手onTouch方法了:

我们利用event.getX()以及event.getY()获取我们当前触摸点,这里很重要,我们判断点是否被点亮的关键就在于该点是否在子控件TextView中

下面是判断触摸点是否在子视图内的方法

关键就在于 该点与每一个子视图的位置关系;

private ImageView viewcontainedPoint(float x,float y){

for(ImageView iv:dotViews){

int[] point=new int[2];

iv.getLocationInWindow(point);

int px=point[0];

int py=point[1];

if((x>=px)&&(x<=px+iv.getWidth())&&(y>=py)&&(y<=py+iv.getHeight())){

return iv;

}

}

return null;

}

onTouch方法:

@Override

public boolean onTouchEvent(MotionEvent event) {

float x=event.getX();

float y=event.getY();

ImageView dot;//判断是否选中的点

switch (event.getAction()){

case MotionEvent.ACTION_DOWN:

dot=viewcontainedPoint(x,y);

if(dot!=null){

dot.setVisibility(VISIBLE);

startPoint=new Point((int)(dot.getPivotX()+dot.getX()),(int)(dot.getPivotY()+dot.getY()));

selectedViews.add(dot);

}

break;

case MotionEvent.ACTION_MOVE:

dot = viewcontainedPoint(x,y);

if (dot == null){

//划线

endPoint = new Point((int)x,(int)y);

//刷新

invalidate();

}else{

//判断是第一个点还是其他

if (startPoint == null){

//第一个点

dot.setVisibility(VISIBLE);

selectedViews.add(dot);

//设置起始点

startPoint = new Point((int)(dot.getPivotX() + dot.getX()),

(int)(dot.getPivotY() + dot.getY()));

}else{

//点亮点

dot.setVisibility(VISIBLE);

//在之前和现在的点之间产生一个path

Path path = new Path();

path.moveTo(startPoint.x,startPoint.y);

path.lineTo(dot.getPivotX() + dot.getX(),

dot.getPivotY() + dot.getY());

if(!selectedViews.contains(dot)){

selectedViews.add(dot);

}

paths.add(path);

//当前这个这个点就是起始点

//设置起始点

startPoint = new Point((int)(dot.getPivotX() + dot.getX()),

(int)(dot.getPivotY() + dot.getY()));

//刷新

invalidate();

}

}

break;

case MotionEvent.ACTION_UP:

savePassword();

clear();

break;

}

return true;

}

注意:由于在滑动过程中 当前点只与上一个点直接画直线,所以我们“上一个点”需要不断地更新

最后就是密码的保存问题了:

由于我们是利用控件的Tag值来组合成密码,所以我们选择SharedPreferences存储,

关于SharedPreferences,可以去看https://blog.csdn.net/u013441613/article/details/80361817

比较详细了;

密码的保存,与“痕迹”的清除

private void clear(){

for(ImageView dot:selectedViews){

dot.setVisibility(INVISIBLE);

}

selectedViews.clear();

paths.clear();

password.clear();

startPoint=null;

endPoint=null;

invalidate();

}

private void savePassword(){

for(ImageView dot:selectedViews){

//password.add((String) dot.getTag());

password.add(dot.getTag().toString());

}

String orgpassword=sp.getString("password",null);

if(orgpassword==null){//第一次———需要保存密码

if(firstpassword==null){

firstpassword=password.toString();

alerttextView.setText("请再次输入密码");

}else {

if(firstpassword.equals(password.toString())){

editor.putString("password", String.valueOf(password));

editor.commit();

alerttextView.setText("密码保存成功");

}else{

alerttextView.setText("两次密码不一致,请重新输入");

firstpassword=null;

}

}

}else{//不是第一次——判断密码是否正确

if(orgpassword.equals(password.toString())){

alerttextView.setText("密码正确");

}else{

alerttextView.setText("密码错误");

}

}

}

最后加入一个小思考:我们在组合成密码时,由于Move方法会被执行很多次,也就是说当我们在某一个控件上移动时(此时触摸位置并没有离开该控件),密码中会组合很多重复的数字,也就是在Move方法被执行了很多次,我们目前的解决方法是加入一个判断,当该点没有被加入密码中时,则加入密码。

但是当我们需要有重复密码时:或许我们可以判断滑动的方法来判断是否加入密码,即如果我们从外向里滑入控件时,我们选择加入密码,若是从里向外或者只是在里面滑动,我们就可以不加入密码;

贴上所有的代码:

XML:

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity"

android:id="@+id/rl_root">

android:id="@+id/iv_bg"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:src="@drawable/bg"

android:scaleType="center"/>

android:layout_width="200dp"

android:layout_height="100dp"

android:layout_marginTop="100dp"

android:layout_marginLeft="120dp"

android:textColor="#0f0"

android:textSize="20dp"

android:id="@+id/tv_alertText"/>

MainActivity:

public class MainActivity extends AppCompatActivity {

RelativeLayout rl;

ArrayList dotViews;

DrawView dv;

float padding;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

dotViews=new ArrayList<>();

setContentView(R.layout.activity_main);

//初始化9个正常点

initNineDot(R.drawable.normal, View.VISIBLE,false);

initDrawView();

//初始化9个高光点

initNineDot(R.drawable.selected,View.INVISIBLE,true);

//将所以点的数组 转递给DrawView

dv.setDotViews(dotViews);

TextView textView=findViewById(R.id.tv_alertText);

dv.setAlerttextView(textView);

}

private void initNineDot(int res,int visiable,boolean record) {

rl = findViewById(R.id.rl_root);

padding = pixelFromDp(40);

//计算两点中心点之间的距离

Point p = new Point();

getWindowManager().getDefaultDisplay().getSize(p);

//获取图片

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.normal);

float space = (p.x - 2 * padding - bitmap.getWidth()) / 2;

//计算起始点的坐标

float x = padding;

float y = p.y / 2 - space - bitmap.getHeight();

if (!record) {

for (int i = 0; i < 3; i++) {

for (int j = 0; j < 3; j++) {

creatDot(res, (int) (y + space * i), (int) (x + space * j), visiable,0);

}

}

}else{

int index=1;

for (int i = 0; i < 3; i++) {

for (int j = 0; j < 3; j++) {

creatDot(res, (int) (y + space * i), (int) (x + space * j), visiable,index);

index++;

}

}

}

}

private void initDrawView(){

dv=new DrawView(this);

RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

rl.addView(dv);

}

private float pixelFromDp(float size){

return size= size*getResources().getDisplayMetrics().density;

}

private void creatDot(int res,int top,int left,int visiable,int index){

ImageView selected=new ImageView(this);

selected.setBackgroundResource(res);

selected.setTag(index);

RelativeLayout.LayoutParams parmas=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

parmas.leftMargin= left;

parmas.topMargin= top;

selected.setVisibility(visiable);

rl.addView(selected,parmas);

//判断res是否是selected 则要加入ImageView数组中

if(res==R.drawable.selected){

dotViews.add(selected);

}

}

}

DrawView:

public class DrawView extends View {

private ArrayList dotViews;

Point startPoint,endPoint;

Paint paint;

private ArrayList paths;

private ArrayList selectedViews;

private ArrayList password;

String firstpassword=null;

private TextView alerttextView;

SharedPreferences sp;

SharedPreferences.Editor editor;

public DrawView(Context context) {

super(context);

//setBackgroundColor(Color.YELLOW);

init();

}

public DrawView(Context context, AttributeSet attrs) {

super(context, attrs);

}

private void init(){

paint=new Paint(Paint.ANTI_ALIAS_FLAG);

paint.setColor(Color.YELLOW);

paint.setStrokeWidth(10);

paint.setStyle(Paint.Style.STROKE);

paths = new ArrayList<>();

selectedViews=new ArrayList<>();

password=new ArrayList<>();

sp=getContext().getSharedPreferences("password",Context.MODE_PRIVATE);

editor=sp.edit();

}

public ArrayList getDotViews() {

return dotViews;

}

public void setAlerttextView(TextView alerttextView) {

this.alerttextView = alerttextView;

}

public void setDotViews(ArrayList dotViews) {

this.dotViews = dotViews;

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

judgment();

super.onSizeChanged(w, h, oldw, oldh);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

float x=event.getX();

float y=event.getY();

ImageView dot;//判断是否选中的点

switch (event.getAction()){

case MotionEvent.ACTION_DOWN:

dot=viewcontainedPoint(x,y);

if(dot!=null){

dot.setVisibility(VISIBLE);

startPoint=new Point((int)(dot.getPivotX()+dot.getX()),(int)(dot.getPivotY()+dot.getY()));

selectedViews.add(dot);

}

break;

case MotionEvent.ACTION_MOVE:

dot = viewcontainedPoint(x,y);

if (dot == null){

//划线

endPoint = new Point((int)x,(int)y);

//刷新

invalidate();

}else{

//判断是第一个点还是其他

if (startPoint == null){

//第一个点

dot.setVisibility(VISIBLE);

selectedViews.add(dot);

//设置起始点

startPoint = new Point((int)(dot.getPivotX() + dot.getX()),

(int)(dot.getPivotY() + dot.getY()));

}else{

//点亮点

dot.setVisibility(VISIBLE);

//在之前和现在的点之间产生一个path

Path path = new Path();

path.moveTo(startPoint.x,startPoint.y);

path.lineTo(dot.getPivotX() + dot.getX(),

dot.getPivotY() + dot.getY());

if(!selectedViews.contains(dot)){

selectedViews.add(dot);

}

paths.add(path);

//当前这个这个点就是起始点

//设置起始点

startPoint = new Point((int)(dot.getPivotX() + dot.getX()),

(int)(dot.getPivotY() + dot.getY()));

//刷新

invalidate();

}

}

break;

case MotionEvent.ACTION_UP:

savePassword();

clear();

break;

}

return true;

}

//判断触摸点是否在某个dot内

private ImageView viewcontainedPoint(float x,float y){

for(ImageView iv:dotViews){

int[] point=new int[2];

iv.getLocationInWindow(point);

int px=point[0];

int py=point[1];

if((x>=px)&&(x<=px+iv.getWidth())&&(y>=py)&&(y<=py+iv.getHeight())){

return iv;

}

}

return null;

}

@Override

protected void onDraw(Canvas canvas) {

if (paths.size() > 0){

for (Path path: paths){

canvas.drawPath(path, paint);

}

}

if (startPoint != null && endPoint != null) {

canvas.drawLine(startPoint.x, startPoint.y,

endPoint.x, endPoint.y, paint);

}

}

private void clear(){

for(ImageView dot:selectedViews){

dot.setVisibility(INVISIBLE);

}

selectedViews.clear();

paths.clear();

password.clear();

startPoint=null;

endPoint=null;

invalidate();

}

private void savePassword(){

for(ImageView dot:selectedViews){

//password.add((String) dot.getTag());

password.add(dot.getTag().toString());

}

String orgpassword=sp.getString("password",null);

if(orgpassword==null){//第一次———需要保存密码

if(firstpassword==null){

firstpassword=password.toString();

alerttextView.setText("请再次输入密码");

}else {

if(firstpassword.equals(password.toString())){

editor.putString("password", String.valueOf(password));

editor.commit();

alerttextView.setText("密码保存成功");

}else{

alerttextView.setText("两次密码不一致,请重新输入");

firstpassword=null;

}

}

}else{//不是第一次——判断密码是否正确

if(orgpassword.equals(password.toString())){

alerttextView.setText("密码正确");

}else{

alerttextView.setText("密码错误");

}

}

}

private void judgment(){

String orgpassword=sp.getString("password",null);

if(orgpassword==null){

alerttextView.setText("请绘制密码");

}

}

//修改密码

private void changePassword(){

editor.clear();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值