1.收獲
這個(gè)圖案解鎖的demo算是完成了洪己,盡管大部分都是在被帶的情況下完成的,但是由于實(shí)踐的問題妥凳,沒有完成,可是自己不可能就不會(huì)做了答捕,畢竟都做了這么多了逝钥,就算有再多的難點(diǎn)都要把他給做了,這不僅僅是去完成任務(wù)拱镐,更是去鍛煉自己好機(jī)會(huì)艘款,自己要好好把握,說是話當(dāng)我自己做完后沃琅,在其中的技術(shù)沒有多難哗咆,姿勢在解決某些問題上會(huì)想不到一些方法,這也許是我寫的東西太少的原因益眉,在遇到問題時(shí)不知道用什么方法去解決晌柬。所以自己還是要多去動(dòng)手寫,奪取看以前學(xué)過和寫過的東西郭脂,這也許對自己有很大的幫助年碘。雖然這一個(gè)月的集訓(xùn)結(jié)束了但是我們學(xué)習(xí)沒有結(jié)束,我們的步伐沒有停止展鸡。加油屿衅!
2.技術(shù)
(1)onTouch事件
(2)使用tag標(biāo)記子控件以及利用tag查找子控件
(3)sharedPreferences保存數(shù)據(jù)
(4)圖案解鎖完整實(shí)現(xiàn)
3.技術(shù)的實(shí)際應(yīng)用和實(shí)踐
(1)onTouch事件
在我們對屏幕進(jìn)行操作時(shí),是如何來實(shí)現(xiàn)事件的調(diào)用和執(zhí)行的方法
在onTouch中我們需要判斷我們的觸摸點(diǎn)是否在那個(gè)控件之內(nèi)娱颊,當(dāng)我們移動(dòng)的時(shí)候會(huì)有什么樣的情況傲诵,當(dāng)我們手指離開屏幕時(shí)回事什么樣的情況凯砍。在我們這個(gè)demo中只有三種情況,點(diǎn)一下拴竹,移動(dòng)悟衩,手指離開,它們分別用ACTION_DOWN,ACTION_MOVE,ACTION_UP來表示栓拜,當(dāng)然在其中有很多的需要判斷座泳。
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標(biāo)記子控件以及利用tag查找子控件
當(dāng)我們觸摸后或者要想使控件有什么變化,那我們怎末去找這個(gè)控件呢幕与,那我們給他一個(gè)Tag值來找他挑势。
這項(xiàng)工作在設(shè)置控件的時(shí)候一起完成,并且我們要記錄這些tag值啦鸣,后來就可以通過這些tag的值去尋找對應(yīng)的控件潮饱,在這些控件中有的控件值是不用記錄的,因?yàn)橛械目丶俏恢煤痛笮∫粯拥慕敫皇浅霈F(xiàn)的時(shí)間不一樣香拉,那麼我們可以將這些控件的tag的值在設(shè)置的時(shí)候有關(guān)系的設(shè)置。
//創(chuàng)建橫線以及對tag值的設(shè)置
//12 23
//45 56
//78 89
tag=12;
for(int i=0;i<3;i++){
for (int j = 0; j < 2; j++) {
//創(chuàng)建一個(gè)視圖顯示線
ImageView lineView=new ImageView(this);
ImageView lineViewwrong=new ImageView(this);
lineView.setTag(tag);
lineViewwrong.setTag(tag+100);
lineTagsList.add(tag);
tag+=11;//同一行相差11
//設(shè)置圖片
lineView.setBackgroundResource(R.drawable.normal_highlight1);
lineViewwrong.setBackgroundResource(R.drawable.wrong_highlight1);
//隱藏視圖
lineView.setVisibility(View.INVISIBLE);
lineViewwrong.setVisibility(View.INVISIBLE);
//創(chuàng)建布局參數(shù)
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;
}
//創(chuàng)建豎線以及對相應(yīng)控件進(jìn)行tag值設(shè)置
//14 25 36
//47 58 69
tag=14;
for(int i=0;i<2;i++){
for (int j = 0; j < 3; j++) {
//創(chuàng)建一個(gè)視圖顯示線
ImageView lineView=new ImageView(this);
ImageView lineViewwrong=new ImageView(this);
lineView.setTag(tag);
lineViewwrong.setTag(tag+100);
//添加到數(shù)組中
lineTagsList.add(tag);
tag+=11;
//設(shè)置圖片
lineView.setBackgroundResource(R.drawable.normal_highlight2);
lineViewwrong.setBackgroundResource(R.drawable.wrong_highlight2);
//隱藏視圖
lineView.setVisibility(View.INVISIBLE);
lineViewwrong.setVisibility(View.INVISIBLE);
//創(chuàng)建布局參數(shù)
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);
}
}
//創(chuàng)建右豎線以及對相應(yīng)控件進(jìn)行tag值進(jìn)行設(shè)置
//15 26
//48 59
tag=15;
for(int i=0;i<2;i++){
for (int j = 0; j < 2; j++) {
//創(chuàng)建一個(gè)視圖顯示線
ImageView lineView=new ImageView(this);
ImageView lineViewwrong=new ImageView(this);
lineView.setTag(tag);
lineViewwrong.setTag(tag+100);
//添加到數(shù)組中
lineTagsList.add(tag);
tag+=11;
//隱藏視圖
lineView.setVisibility(View.INVISIBLE);
lineViewwrong.setVisibility(View.INVISIBLE);
//設(shè)置圖片
lineView.setBackgroundResource(R.drawable.normal_highlight3);
lineViewwrong.setBackgroundResource(R.drawable.wrong_highlight3);
//創(chuàng)建布局參數(shù)
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;
}
//創(chuàng)建左豎線以及tag的設(shè)置
//24 35
//57 68
tag=24;
for(int i=0;i<2;i++){
for (int j = 0; j < 2; j++) {
//創(chuàng)建一個(gè)視圖顯示線
ImageView lineView=new ImageView(this);
ImageView lineViewwrong=new ImageView(this);
lineView.setTag(tag);
lineViewwrong.setTag(tag+100);
//添加到數(shù)組中
lineTagsList.add(tag);
tag+=11;
//隱藏視圖
lineView.setVisibility(View.INVISIBLE);
lineViewwrong.setVisibility(View.INVISIBLE);
//設(shè)置圖片
lineView.setBackgroundResource(R.drawable.normal_highlight4);
lineViewwrong.setBackgroundResource(R.drawable.wrong_highlight4);
//創(chuàng)建布局參數(shù)
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;
}
//對九個(gè)點(diǎn)進(jìn)行tag值設(shè)置
tag=1;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//創(chuàng)建用于顯示點(diǎn)的視圖
ImageView dotView=new ImageView(this);
ImageView dotViewwrong=new ImageView(this);
//設(shè)置對應(yīng)tag值
dotView.setTag(tag);
dotViewwrong.setTag(tag+100);
tag++;
//隱藏視圖
dotView.setVisibility(View.INVISIBLE);
dotViewwrong.setVisibility(View.INVISIBLE);
//顯示對應(yīng)的圖片
dotView.setBackgroundResource(R.drawable.selected_dot);
dotViewwrong.setBackgroundResource(R.drawable.wrong_dot);
//創(chuàng)建控件的尺寸
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);
//將這個(gè)控件添加到數(shù)組中
dotsList.add(dotView);
wrongList.add(dotViewwrong);
}
}
}
}
當(dāng)我們把每個(gè)控件的tag值設(shè)置完后中狂,對后面的工作有了很大的幫助凫碌。
(3)sharedPreferences保存數(shù)據(jù)
在我們進(jìn)行的過程中,我們需要將一些數(shù)據(jù)進(jìn)行保存胃榕,比如密碼之類的盛险,在這里我們應(yīng)用sharedPreferences進(jìn)行保存數(shù)據(jù),當(dāng)然我們可以用文件進(jìn)行保存數(shù)據(jù)勋又。
在 Android數(shù)據(jù)儲(chǔ)存4種
- 1.sharedPreference 偏好設(shè)置
- 2.file
- 3.sqlite3
- 4.network
但是當(dāng)我們在讀取數(shù)據(jù)的時(shí)候苦掘,也需要判斷一些內(nèi)容
//查找偏好這種里面是否有保存的密碼pwd
SharedPreferences sp=getSharedPreferences("password",MODE_PRIVATE);
//獲取pwd對應(yīng)的密碼
orgpassword=sp.getString("pwd",null);
String pwd=sp.getString("pwd",null);
if(pwd==null){
alertTextView.setText("請?jiān)O(shè)置密碼圖案");
}else{
alertTextView.setText("請繪制密碼圖案");
}
}
}
(4)圖案解鎖完整實(shí)現(xiàn)
在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"/>
//定義一個(gè)數(shù)組 保存每個(gè)點(diǎn)的控件
ArrayList<ImageView> dotsList;
ArrayList<Integer> lineTagsList;
ArrayList<ImageView> selectedList;//所有被選中的視圖
ArrayList<ImageView> wrongList;//所有紅色的控件
int tag;
//保存上一個(gè)被點(diǎn)亮的對象
ImageView lastSelectedDot=null;
//記錄滑動(dòng)的密碼
StringBuilder password;
//保存原始密碼
String orgpassword;
//保存第一次輸入的密碼
String FirstPassword;
//提示文本視圖
TextView alertTextView;```
我們需要一個(gè)函數(shù)來進(jìn)行判斷一個(gè)事件是否在一定的范圍內(nèi)
//寫一個(gè)方法 判斷某個(gè)點(diǎn)是否在某個(gè)控件內(nèi)部
public ImageView dotOfTouch(float x,float y){
for(ImageView dot:dotsList){
//獲取dot相對于屏幕的坐標(biāo)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;
}
當(dāng)我們的手指在一個(gè)點(diǎn)時(shí)
case MotionEvent.ACTION_DOWN:
//按下
//獲取觸摸點(diǎn)的坐標(biāo)
x=event.getX();
y=event.getY();
//判斷 x y是不是在某個(gè)點(diǎn)的范圍內(nèi)
selected=dotOfTouch(x,y);
//點(diǎn)亮
if(selected!=null){
selected.setVisibility(View.VISIBLE);
//記錄
lastSelectedDot=selected;
//將tag值拼接到密碼中
password.append(selected.getTag());
//將點(diǎn)亮的點(diǎn)添加到數(shù)組中
selectedList.add(selected);
}
break;
當(dāng)我們手指在移動(dòng)的時(shí)候
case MotionEvent.ACTION_MOVE:
//移動(dòng)
//獲取觸摸點(diǎn)的坐標(biāo)
x=event.getX();
y=event.getY();
//判斷 x y是不是在某個(gè)點(diǎn)的范圍內(nèi)
selected=dotOfTouch(x,y);
//點(diǎn)亮
if(selected!=null){
//判斷是不是第一個(gè)點(diǎn)
if(lineTagsList==null){
selected.setVisibility(View.VISIBLE);
//記錄
lastSelectedDot=selected;
//將點(diǎn)亮的點(diǎn)添加到數(shù)組中
selectedList.add(selected);
//將tag值拼接到密碼中
password.append(selected.getTag());
}else{
//判斷是否已經(jīng)被點(diǎn)亮
if(selectedList.contains(selected)!=true){
//不是第一個(gè)點(diǎn)
//獲取上一個(gè)點(diǎn)和當(dāng)前點(diǎn)的tag組成線的tag
int ltag=(Integer) lastSelectedDot.getTag();
int ctag=(Integer) selected.getTag();
//獲取兩個(gè)點(diǎn)連線的tag值
int lineTag=ltag>ctag?ctag*10+ltag: ltag*10+ctag;
if(lineTagsList.contains(lineTag)){
//線存在
selected.setVisibility(View.VISIBLE);
//將點(diǎn)亮的點(diǎn)添加到數(shù)組中
selectedList.add(selected);
//將tag值拼接到密碼中
password.append(selected.getTag());
//點(diǎn)亮線
//找到當(dāng)前容器
RelativeLayout rl=findViewById(R.id.rootlayout);
//通過tag找到子控件
ImageView iv=rl.findViewWithTag(lineTag);
//點(diǎn)亮線
iv.setVisibility(View.VISIBLE);
selectedList.add(iv);
lastSelectedDot=selected;
}
}
}
}
break;
當(dāng)我們的手指在離開屏幕時(shí)
case MotionEvent.ACTION_UP:
//離開
// 1.繪制密碼 和原始密碼進(jìn)行比較
//2.設(shè)置密碼 第一次
//3.設(shè)置密碼 第二次
//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;
//找到當(dāng)前容器
RelativeLayout rl=findViewById(R.id.rootlayout);
//通過tag找到子控件
ImageView iv=rl.findViewWithTag(i);
if(wrongList.contains(iv)){
//點(diǎn)亮
iv.setVisibility(View.VISIBLE);
}
}
alertTextView.setText("解鎖密碼失敗");
}
}else{
//設(shè)置密碼
//判斷是第一次還是第二次確認(rèn)密碼
if(FirstPassword==null){
//設(shè)置密碼地第一次
FirstPassword=password.toString();
//提示確認(rèn)密碼圖案
alertTextView.setText("請確認(rèn)密碼圖案");
}else{
//第二次確認(rèn)密碼
//判斷兩次密碼是否一致
if(FirstPassword.equals(password.toString())){
//設(shè)置成功
alertTextView.setText("設(shè)置密碼成功");
//保存密碼
SharedPreferences sp=getSharedPreferences("password",MODE_PRIVATE);
SharedPreferences.Editor editor=sp.edit();
editor.putString("pwd",FirstPassword);
editor.commit();
}else{
//設(shè)置失敗
for(ImageView imageView:selectedList){
int i = (Integer) (imageView.getTag())+100;
//找到當(dāng)前容器
RelativeLayout rl=findViewById(R.id.rootlayout);
//通過tag找到子控件
ImageView iv=rl.findViewWithTag(i);
if(wrongList.contains(iv)){
//點(diǎn)亮`
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;
}
其中我們的代碼中出現(xiàn)了方法clean()和close()
clean()方法的作用是清除第一次的手勢密碼和使一些控件透明
//清空
public void clean() {
password.setLength(0);
for(ImageView iv:selectedList) {
iv.setVisibility(View.INVISIBLE);
}
}
close()方法也是是一些手勢密碼錯(cuò)誤控件透明楔壤,并使延長執(zhí)行透明代碼的時(shí)間
public void close() {
for(ImageView iv:selectedList) {
int i = (Integer) (iv.getTag())+100;
//找到當(dāng)前容器
RelativeLayout rl=findViewById(R.id.rootlayout);
//通過tag找到子控件
ImageView imageView=rl.findViewWithTag(i);
imageView.setVisibility(View.INVISIBLE);
}
//清空數(shù)組
selectedList.clear();
}
效果:
設(shè)置密碼
確認(rèn)密碼
輸入密碼