1.收獲
這個圖案解鎖的demo算是完成了,盡管大部分都是在被帶的情況下完成的,但是由于實踐的問題,沒有完成,可是自己不可能就不會做了,畢竟都做了這么多了,就算有再多的難點都要把他給做了,這不僅僅是去完成任務,更是去鍛煉自己好機會,自己要好好把握,說是話當我自己做完后,在其中的技術沒有多難,姿勢在解決某些問題上會想不到一些方法,這也許是我寫的東西太少的原因,在遇到問題時不知道用什么方法去解決。所以自己還是要多去動手寫,奪取看以前學過和寫過的東西,這也許對自己有很大的幫助。雖然這一個月的集訓結束了但是我們學習沒有結束,我們的步伐沒有停止。加油!
2.技術
(1)onTouch事件
(2)使用tag標記子控件以及利用tag查找子控件
(3)sharedPreferences保存數據
(4)圖案解鎖完整實現
3.技術的實際應用和實踐
(1)onTouch事件
在我們對屏幕進行操作時,是如何來實現事件的調用和執行的方法
在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();
}
效果:
設置密碼
確認密碼
輸入密碼