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閱讀 228,363評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容

  • (一)知識準備 事件處理機制: 什么是事件處理機制?比如我們點擊QQ登錄界面上的登錄按鈕,我們就向服務器發送了一個...
    颵麏閱讀 569評論 0 5
  • ¥開啟¥ 【iAPP實現進入界面執行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,483評論 0 17
  • 一、簡歷準備 1、個人技能 (1)自定義控件、UI設計、常用動畫特效 自定義控件 ①為什么要自定義控件? Andr...
    lucas777閱讀 5,229評論 2 54
  • Swift1> Swift和OC的區別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,120評論 1 32
  • 第242章:特殊的生日 “咿咿......”小玉清見歐陽震剛對自己爺爺大吼,嘴里發出咿呀呀呀的聲音,拿小手指著他。...
    墨棠子閱讀 645評論 3 13