Android的学习与实践3 (图案解锁后续部分)

1.收获

这个图案解锁的demo算是完成了,尽管大部分都是在被带的情况下完成的,但是由于实践的问题,没有完成,可是自己不可能就不会做了,毕竟都做了这么多了,就算有再多的难点都要把他给做了,这不仅仅是去完成任务,更是去锻炼自己好机会,自己要好好把握,说是话当我自己做完后,在其中的技术没有多难,姿势在解决某些问题上会想不到一些方法,这也许是我写的东西太少的原因,在遇到问题时不知道用什么方法去解决。所以自己还是要多去动手写,夺取看以前学过和写过的东西,这也许对自己有很大的帮助。虽然这一个月的集训结束了但是我们学习没有结束,我们的步伐没有停止。加油!

2.技术

(1)onTouch事件
(2)使用tag标记子控件以及利用tag查找子控件
(3)sharedPreferences保存数据
(4)图案解锁完整实现

3.技术的实际应用和实践

(1)onTouch事件
在我们对屏幕进行操作时,是如何来实现事件的调用和执行的方法

image.png

在onTouch中我们需要判断我们的触摸点是否在那个控件之内,当我们移动的时候会有什么样的情况,当我们手指离开屏幕时回事什么样的情况。在我们这个demo中只有三种情况,点一下,移动,手指离开,它们分别用ACTION_DOWN,ACTION_MOVE,ACTION_UP来表示,当然在其中有很多的需要判断。

public boolean onTouchEvent(MotionEvent event) {
//获取事件的类型
        int action=event.getAction();
//判断是什么事件
switch(action){
 case MotionEvent.ACTION_DOWN:
    break;
 case MotionEvent.ACTION_MOVE:
    break;
 case MotionEvent.ACTION_UP:
     break;
default:
 break;
   }
}

(2)使用tag标记子控件以及利用tag查找子控件
当我们触摸后或者要想使控件有什么变化,那我们怎末去找这个控件呢,那我们给他一个Tag值来找他。


这项工作在设置控件的时候一起完成,并且我们要记录这些tag值,后来就可以通过这些tag的值去寻找对应的控件,在这些控件中有的控件值是不用记录的,因为有的控件是位置和大小一样的,只是出现的时间不一样,那麽我们可以将这些控件的tag的值在设置的时候有关系的设置。

//创建横线以及对tag值的设置

            //12 23
            //45 56
            //78 89
            tag=12;
            for(int i=0;i<3;i++){
                for (int j = 0; j < 2; j++) {
                    //创建一个视图显示线
                    ImageView lineView=new ImageView(this);
                    ImageView lineViewwrong=new ImageView(this);

                    lineView.setTag(tag);
                    lineViewwrong.setTag(tag+100);

                    lineTagsList.add(tag);

                    tag+=11;//同一行相差11
                    //设置图片
                    lineView.setBackgroundResource(R.drawable.normal_highlight1);
                    lineViewwrong.setBackgroundResource(R.drawable.wrong_highlight1);

                    //隐藏视图
                    lineView.setVisibility(View.INVISIBLE);
                    lineViewwrong.setVisibility(View.INVISIBLE);

                    //创建布局参数
                    RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
                    params.leftMargin=(int)(x+46.6*a+99*a*j);
                    params.topMargin=(int)(y+170*a+99*a*i);

                    rl.addView(lineView,params);
                    rl.addView(lineViewwrong,params);

                    wrongList.add(lineViewwrong);
                }
                //换一行 相差22
                tag+=11;
            }

//创建竖线以及对相应控件进行tag值设置

            //14 25 36
            //47 58 69
            tag=14;
            for(int i=0;i<2;i++){
                for (int j = 0; j < 3; j++) {
                    //创建一个视图显示线
                    ImageView lineView=new ImageView(this);
                    ImageView lineViewwrong=new ImageView(this);
                    lineView.setTag(tag);
                    lineViewwrong.setTag(tag+100);
                    //添加到数组中
                    lineTagsList.add(tag);
                    tag+=11;

                    //设置图片
                    lineView.setBackgroundResource(R.drawable.normal_highlight2);
                    lineViewwrong.setBackgroundResource(R.drawable.wrong_highlight2);
                    //隐藏视图
                    lineView.setVisibility(View.INVISIBLE);
                    lineViewwrong.setVisibility(View.INVISIBLE);
                    //创建布局参数
                    RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
                    params.leftMargin=(int)(x+42*a+99*a*j);
                    params.topMargin=(int)(y+170*a+99*a*i);

                    rl.addView(lineView,params);
                    rl.addView(lineViewwrong,params);

                    wrongList.add(lineViewwrong);
                }
            }

//创建右竖线以及对相应控件进行tag值进行设置

            //15 26
            //48 59
            tag=15;
            for(int i=0;i<2;i++){
                for (int j = 0; j < 2; j++) {
                    //创建一个视图显示线
                    ImageView lineView=new ImageView(this);
                    ImageView lineViewwrong=new ImageView(this);
                    lineView.setTag(tag);
                    lineViewwrong.setTag(tag+100);
                    //添加到数组中
                    lineTagsList.add(tag);
                    tag+=11;
                    //隐藏视图
                    lineView.setVisibility(View.INVISIBLE);
                    lineViewwrong.setVisibility(View.INVISIBLE);
                    //设置图片
                    lineView.setBackgroundResource(R.drawable.normal_highlight3);
                    lineViewwrong.setBackgroundResource(R.drawable.wrong_highlight3);
                    //创建布局参数
                    RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
                    params.leftMargin=(int)(x+42*a+99*a*j);
                    params.topMargin=(int)(y+170*a+99*a*i);
                    rl.addView(lineView,params);
                    rl.addView(lineViewwrong,params);
                    wrongList.add(lineViewwrong);
                }
                tag+=11;
            }

//创建左竖线以及tag的设置

            //24 35
            //57 68
            tag=24;
            for(int i=0;i<2;i++){
                for (int j = 0; j < 2; j++) {
                    //创建一个视图显示线
                    ImageView lineView=new ImageView(this);
                    ImageView lineViewwrong=new ImageView(this);
                    lineView.setTag(tag);
                    lineViewwrong.setTag(tag+100);
                    //添加到数组中
                    lineTagsList.add(tag);
                    tag+=11;
                    //隐藏视图
                    lineView.setVisibility(View.INVISIBLE);
                    lineViewwrong.setVisibility(View.INVISIBLE);
                    //设置图片
                    lineView.setBackgroundResource(R.drawable.normal_highlight4);
                    lineViewwrong.setBackgroundResource(R.drawable.wrong_highlight4);
                    //创建布局参数
                    RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
                    params.leftMargin=(int)(x+54*a+99*a*j);
                    params.topMargin=(int)(y+170*a+99*a*i);
                    rl.addView(lineView,params);
                    rl.addView(lineViewwrong,params);
                    wrongList.add(lineViewwrong);
                }
                tag+=11;
            }

//对九个点进行tag值设置

            tag=1;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    //创建用于显示点的视图
                    ImageView dotView=new ImageView(this);
                    ImageView dotViewwrong=new ImageView(this);
                    //设置对应tag值
                    dotView.setTag(tag);
                    dotViewwrong.setTag(tag+100);
                    tag++;
                    //隐藏视图
                    dotView.setVisibility(View.INVISIBLE);
                    dotViewwrong.setVisibility(View.INVISIBLE);
                    //显示对应的图片
                    dotView.setBackgroundResource(R.drawable.selected_dot);
                    dotViewwrong.setBackgroundResource(R.drawable.wrong_dot);
                    //创建控件的尺寸
                    RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

                    params.leftMargin=(int)(x+35*a+99*a*j);
                    params.topMargin=(int)(y+164*a+99*a*i);

                    //将子控件添加到容器中
                    rl.addView(dotView,params);
                    rl.addView(dotViewwrong,params);

                    //将这个控件添加到数组中
                    dotsList.add(dotView);
                    wrongList.add(dotViewwrong);

                }
            }
        }
    }

当我们把每个控件的tag值设置完后,对后面的工作有了很大的帮助。

(3)sharedPreferences保存数据
在我们进行的过程中,我们需要将一些数据进行保存,比如密码之类的,在这里我们应用sharedPreferences进行保存数据,当然我们可以用文件进行保存数据。
在 Android数据储存4种

  • 1.sharedPreference 偏好设置
  • 2.file
  • 3.sqlite3
  • 4.network
    但是当我们在读取数据的时候,也需要判断一些内容
//查找偏好这种里面是否有保存的密码pwd
        SharedPreferences sp=getSharedPreferences("password",MODE_PRIVATE);
        //获取pwd对应的密码
        orgpassword=sp.getString("pwd",null);
        String pwd=sp.getString("pwd",null);
        if(pwd==null){
            alertTextView.setText("请设置密码图案");
        }else{
            alertTextView.setText("请绘制密码图案");
        }
    }
}

(4)图案解锁完整实现
在xml文件中显示文本。

 <!--显示文本-->
    <TextView
        android:id="@+id/tv_alert"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请绘制密码图案"
        android:textSize="25sp"
        android:textColor="#ffffff"
        android:textAlignment="center"
        android:layout_alignTop="@+id/opview"
        android:layout_marginTop="70dp"/>

//定义一个数组 保存每个点的控件

ArrayList<ImageView> dotsList;
ArrayList<Integer> lineTagsList;
ArrayList<ImageView> selectedList;//所有被选中的视图
ArrayList<ImageView> wrongList;//所有红色的控件
int tag;
//保存上一个被点亮的对象
ImageView lastSelectedDot=null;
//记录滑动的密码
StringBuilder password;
//保存原始密码
String orgpassword;
//保存第一次输入的密码
String FirstPassword;

//提示文本视图
TextView alertTextView;```

我们需要一个函数来进行判断一个事件是否在一定的范围内

//写一个方法 判断某个点是否在某个控件内部
  public ImageView dotOfTouch(float x,float y){
for(ImageView dot:dotsList){
          //获取dot相对于屏幕的坐标x y
          int[] loc=new int[2];
          dot.getLocationOnScreen(loc);
          int dx=loc[0];
          int dy=loc[1];
          //获取偏移量
          int r=dx+dot.getWidth();
          int b=dy+dot.getHeight();
          if((x<=r&&x>=dx)&&(y<=b&&y>=dy)){
              return dot;
          }
      }
      return null;
  }

当我们的手指在一个点时

 case MotionEvent.ACTION_DOWN:
                //按下
                //获取触摸点的坐标
                x=event.getX();
                y=event.getY();
                //判断 x y是不是在某个点的范围内
                selected=dotOfTouch(x,y);
                //点亮
                if(selected!=null){
                    selected.setVisibility(View.VISIBLE);
                    //记录
                    lastSelectedDot=selected;
                    //将tag值拼接到密码中
                    password.append(selected.getTag());
                    //将点亮的点添加到数组中
                    selectedList.add(selected);
                }
                break;

当我们手指在移动的时候

case MotionEvent.ACTION_MOVE:
                //移动
                //获取触摸点的坐标
                x=event.getX();
                y=event.getY();
                //判断 x y是不是在某个点的范围内
                selected=dotOfTouch(x,y);
                //点亮
                if(selected!=null){
                    //判断是不是第一个点
                    if(lineTagsList==null){
                        selected.setVisibility(View.VISIBLE);
                        //记录
                        lastSelectedDot=selected;
                        //将点亮的点添加到数组中
                        selectedList.add(selected);
                        //将tag值拼接到密码中
                        password.append(selected.getTag());
                    }else{
                        //判断是否已经被点亮
                        if(selectedList.contains(selected)!=true){
                            //不是第一个点
                            //获取上一个点和当前点的tag组成线的tag
                            int ltag=(Integer) lastSelectedDot.getTag();
                            int ctag=(Integer) selected.getTag();
                            //获取两个点连线的tag值
                            int lineTag=ltag>ctag?ctag*10+ltag: ltag*10+ctag;
                            if(lineTagsList.contains(lineTag)){
                                //线存在
                                selected.setVisibility(View.VISIBLE);
                                //将点亮的点添加到数组中
                                selectedList.add(selected);
                                //将tag值拼接到密码中
                                password.append(selected.getTag());
                                //点亮线
                                //找到当前容器
                                RelativeLayout rl=findViewById(R.id.rootlayout);
                                //通过tag找到子控件
                                ImageView iv=rl.findViewWithTag(lineTag);
                                //点亮线
                                iv.setVisibility(View.VISIBLE);
                                selectedList.add(iv);
                                lastSelectedDot=selected;
                            }
                        }
                    }
                }
                break;

当我们的手指在离开屏幕时

 case MotionEvent.ACTION_UP:
                //离开
                // 1.绘制密码 和原始密码进行比较
                //2.设置密码 第一次
                //3.设置密码  第二次
                //System.out.println(password.toString());
                if(orgpassword!=null){
                    //有密码
                    if(password.toString().equals(orgpassword)){
                        alertTextView.setText("解锁密码成功");
                    }else{
                        for(ImageView imageView:selectedList){
                            int i = (Integer) (imageView.getTag())+100;
                            //找到当前容器
                            RelativeLayout rl=findViewById(R.id.rootlayout);
                            //通过tag找到子控件
                            ImageView iv=rl.findViewWithTag(i);
                            if(wrongList.contains(iv)){
                                //点亮
                                iv.setVisibility(View.VISIBLE);
                            }
                        }
                        alertTextView.setText("解锁密码失败");
                    }
                }else{
                    //设置密码
                    //判断是第一次还是第二次确认密码
                    if(FirstPassword==null){
                        //设置密码地第一次
                        FirstPassword=password.toString();
                        //提示确认密码图案
                        alertTextView.setText("请确认密码图案");
                    }else{
                        //第二次确认密码
                        //判断两次密码是否一致
                        if(FirstPassword.equals(password.toString())){
                            //设置成功
                            alertTextView.setText("设置密码成功");
                            //保存密码
                            SharedPreferences sp=getSharedPreferences("password",MODE_PRIVATE);
                            SharedPreferences.Editor editor=sp.edit();
                            editor.putString("pwd",FirstPassword);
                            editor.commit();
                        }else{
                            //设置失败
                            for(ImageView imageView:selectedList){
                                int i = (Integer) (imageView.getTag())+100;
                                //找到当前容器
                                RelativeLayout rl=findViewById(R.id.rootlayout);
                                //通过tag找到子控件
                                ImageView iv=rl.findViewWithTag(i);
                                if(wrongList.contains(iv)){
                                    //点亮`
                                    iv.setVisibility(View.VISIBLE);
                                }
                            }
                            alertTextView.setText("两次密码不一致 请重新绘制密码");
                            FirstPassword=null;
                        }
                    }
                }
                //清空
                clean();
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                       close();
                    }
                }, 300);
                break;
            default:
                break;
        }

        return true;
    }

其中我们的代码中出现了方法clean()和close()
clean()方法的作用是清除第一次的手势密码和使一些控件透明

 //清空
    public void clean()  {
        password.setLength(0);
        for(ImageView iv:selectedList) {
            iv.setVisibility(View.INVISIBLE);
        }

    }

close()方法也是是一些手势密码错误控件透明,并使延长执行透明代码的时间

 public void close()  {
        for(ImageView iv:selectedList) {
            int i = (Integer) (iv.getTag())+100;
            //找到当前容器
            RelativeLayout rl=findViewById(R.id.rootlayout);
            //通过tag找到子控件
            ImageView imageView=rl.findViewWithTag(i);
            imageView.setVisibility(View.INVISIBLE);
        }
        //清空数组
        selectedList.clear();
    }

效果:
设置密码


image.png

image.png

确认密码


image.png

image.png

输入密码


image.png
image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容

  • (一)知识准备 事件处理机制: 什么是事件处理机制?比如我们点击QQ登录界面上的登录按钮,我们就向服务器发送了一个...
    颵麏阅读 555评论 0 5
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,365评论 0 17
  • 一、简历准备 1、个人技能 (1)自定义控件、UI设计、常用动画特效 自定义控件 ①为什么要自定义控件? Andr...
    lucas777阅读 5,190评论 2 54
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,090评论 1 32
  • 第242章:特殊的生日 “咿咿......”小玉清见欧阳震刚对自己爷爷大吼,嘴里发出咿呀呀呀的声音,拿小手指着他。...
    墨棠子阅读 624评论 3 13