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();
}
效果:
设置密码
确认密码
输入密码