功能展示:
image.png image.png image.png image.png image.png image.png image.pngXML代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/root_layout"
>
<!-- 背景图片-->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/main_bg"
/>
<ImageView
android:id="@+id/opView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/op_bg"
android:layout_centerInParent="true"
/>
<!--显示文本 -->
<TextView
android:id="@+id/tv_alert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="图案解锁"
android:textSize="20sp"
android:textColor="#ffffff"
android:textAlignment="center"
android:layout_alignTop="@id/opView"
android:layout_marginTop="90dp"
/>
</RelativeLayout>
Mainactivity代码
public class MainActivity extends AppCompatActivity {
static float F;
int tag;
//保存上一次被点亮的点的对象
ImageView lastSelectedDot;
//记录滑动的密码
StringBuilder password;
//提示的文本视图
TextView alertTextView;
//保存原始密码
String orgPassword;
//保存第一次输入的密码
String firstPassword;
//定义一个数组 保存这个点的控件
private ArrayList<ImageView> points;
private ArrayList<Integer> lineTagsList;
private ArrayList<ImageView> selectedList;
float movingX,movingY;
public void onWindowFocusChanged (boolean hasFocus){
float scale = getResources().getDisplayMetrics().density;
F=scale;
super.onWindowFocusChanged(hasFocus);
//判断是否已经显示:
if(hasFocus){
RelativeLayout rl = findViewById(R.id.root_layout);
//获取背景视图
ImageView iv = findViewById(R.id.opView);
//获取x和y坐标
int x= iv.getLeft();
int y = iv.getTop();
tag = 14;
//创建横线6条
for(int i = 0;i<2;i++){
for(int j=0;j<3;j++){
//创建一个视图,用于显示线
ImageView lineView = new ImageView(this);
lineView.setTag(tag);
lineTagsList.add(tag);//保存线的tag值
tag+=11;// 同一行相差11
lineView.setVisibility(View.INVISIBLE);
//设置图片
lineView.setBackgroundResource(R.drawable.normal_highlight2);
//创建布局参数
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int)(x+42*scale)+(int)(99*scale*j);
params.topMargin = (int)(y+170*scale)+(int)(99*scale*i);
rl.addView(lineView,params);
System.out.println(lineView.getTag());
}
//换一行相差 22
}
tag=12;
//添加竖线
for(int i = 0;i<3;i++){
for(int j=0;j<2;j++){
//创建一个视图,用于显示线
ImageView lineView = new ImageView(this);
lineView.setVisibility(View.INVISIBLE);
lineView.setTag(tag);
lineTagsList.add(tag);//保存线的tag值
tag+=11;
//设置图片
lineView.setBackgroundResource(R.drawable.normal_highlight1);
//创建布局参数
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int)(x+46.6*scale)+(int)(99*scale*j);
params.topMargin = (int)(y+170*scale)+(int)(99*scale*i);
rl.addView(lineView,params);
System.out.println(lineView.getTag());
}
tag+=11;
}
//创建右斜线
tag=15;
for(int i = 0;i<2;i++){
for(int j=0;j<2;j++){
//创建一个视图,用于显示线
ImageView rlineView = new ImageView(this);
rlineView.setVisibility(View.INVISIBLE);
rlineView.setTag(tag);
lineTagsList.add(tag);//保存线的tag值
tag+=11;
//设置图片
rlineView.setBackgroundResource(R.drawable.normal_highlight3);
//创建布局参数
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int)(x+46.6*scale)+(int)(99*scale*j);
params.topMargin = (int)(y+170*scale)+(int)(99*scale*i);
rl.addView(rlineView,params);
System.out.println(rlineView.getTag());
}
tag+=11;
}
//添加左斜线
tag=24;
for(int i = 0;i<2;i++){
for(int j=0;j<2;j++){
//创建一个视图,用于显示线
ImageView LlineView = new ImageView(this);
LlineView.setVisibility(View.INVISIBLE);
LlineView.setTag(tag);
lineTagsList.add(tag);//保存线的tag值
tag+=11;
//设置图片
LlineView.setBackgroundResource(R.drawable.normal_highlight4);
//创建布局参数
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int)(x+53.3*scale)+(int)(99*scale*j);
params.topMargin = (int)(y+170*scale)+(int)(99*scale*i);
rl.addView(LlineView,params);
System.out.println(LlineView.getTag());
}
tag+=11;
}
//添加点
tag=1;
for(int i = 0;i<3;i++){
for(int j=0;j<3;j++){
//获取容器
ImageView dotView;
//创建用于显示点的视图
dotView = new ImageView(this);
//设置对应的tag值
dotView.setTag(tag++);
dotView.setVisibility(View.INVISIBLE);
//显示对应的图片
dotView.setBackgroundResource(R.drawable.selected_dot);
//创建控件的尺寸
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int)(x+35*scale) +(int)(99*scale*j);
params.topMargin = (int)(y+162*scale)+(int)(99*scale*i);
//将控件添加到容器中
rl.addView(dotView,params);
//将这个控件添加到数组里面
points.add(dotView);
System.out.println(dotView.getTag());
}
}
}
}
//监听触摸事件
public boolean onTouchEvent( MotionEvent event){
//获取事件的类型
int action = event.getAction();
//判断是什么事件
movingX=event.getX();
movingY= event.getY();
ImageView selected;
float x,y;
switch (action){
case MotionEvent.ACTION_DOWN:
//按下
//获取触摸点的坐标
x= event.getX();
y= event.getY();
selected = dotOfTouch(x,y);
//点亮
if(selected!=null) {
selected.setVisibility(View.VISIBLE);
selectedList.add(selected);
//记录当前这个点
lastSelectedDot = selected;
//将tag值拼接到密码中
password.append(selected.getTag());
}
//checkSelectPoint();
break;
case MotionEvent.ACTION_MOVE:
//移动
x= event.getX();
y= event.getY();
selected = dotOfTouch(x,y);
//点亮
if(selected!=null) {
//判断这个点是不是第一个点
if(lastSelectedDot==null){
//第一个点
selected.setVisibility(View.VISIBLE);
lastSelectedDot = selected;
selectedList.add(selected);
}else{
//不是第一个点
//获取上一个点和当前点的tag组成的线的tag
int lTag= (Integer) lastSelectedDot.getTag();
int cTag= (Integer) selected.getTag();
//获取两个线的tag值 small*10+big
int lineTag = lTag>cTag? cTag*10+lTag:lTag*10+cTag;
//判断线是否存在
if(lineTagsList.contains(lineTag)){
//线存在
//点亮点
selected.setVisibility(View.VISIBLE);
password.append(selected.getTag());
//点亮这条线
//获取容器对象
RelativeLayout rl = findViewById(R.id.root_layout);
//通过tag查找子控件
ImageView iv =rl.findViewWithTag(lineTag);
//点亮线
iv.setVisibility(View.VISIBLE);
selectedList.add(selected);
selectedList.add(iv);
//记录这个点
lastSelectedDot = selected;
}
}
}
break;
case MotionEvent.ACTION_UP:
//离开
// 1.绘制密码 和原始密码比较
//2.设置密码 第一次
//3。设置密码 第二次
if(orgPassword!=null){
if(password.toString().equals(orgPassword)){
alertTextView.setText("解锁密码成功");
}else {
alertTextView.setText("解锁密码失败");
}
}else {
//设置密码
//判断是第一次还是第二次确认密码
//123
if(firstPassword==null){
//设置密码的第一次
firstPassword=password.toString();
//提示确认密码
alertTextView.setText("请确认密码图案");
}else {
//设置密码的第二次
//判断两次是否一致
if(firstPassword.equals(password.toString())){
//设置成功
alertTextView.setText("设置密码成功");
//保存密码
SharedPreferences sp = getSharedPreferences("password",0);
SharedPreferences.Editor editor = sp.edit();
editor.putString("pw",firstPassword);
editor.commit();
}else {
//设置失败
alertTextView.setText("两次密码不一致 请重新设置");
firstPassword =null;
}
}
}
System.out.println(password.toString());
clean();
break;
default:
break;
}
return true;
}
//清空
public void clean(){
password.setLength(0);
//隐藏所有选中的视图 点 线
for(ImageView iv:selectedList){
iv.setVisibility(View.INVISIBLE);
}
//清空数组
selectedList.clear();
}
//判断触摸点是否在某个控件内部
public ImageView dotOfTouch(float x,float y){
/*让触摸点切换到控件的父视图中
//计算状态栏或者标题栏的距离
Point p =new Point();
getWindowManager().getDefaultDisplay().getSize(p);
//获取容器本身的高度
RelativeLayout rl = findViewById(R.id.root_layout);
//计算状态栏的高度
float padding = p.y-rl.getHeight();
*/
/*
//2.让控件切换到屏幕
ImageView first = points.get(0);
int []loc = new int[2];
first.getLocationOnScreen(loc);
System.out.println("相对屏幕:"+loc[1]);
System.out.println("相对容器 y:"+first.getY());
*/
//遍历数组
//获取第一个点
for(ImageView dot:points){
//获取这个dot相对于屏幕的坐标
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;
}
/**
* 安卓中像在容器中添加的控件需要被窗户window计算/测量
* window -> viewGroup ->子控件
* 通常在 onCreate onStrat onResume 无法获取到控件的本身的尺寸
*
* 所有的测量都是在另一个线程操作
* 如果想要获取控件的尺寸
*
* @param savedInstanceState
*/
/**
* Android数据存储4种
* 1.sharedPreference 偏好设置
* 2.file
* 3.sqlite3
* 4.network
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//准备好数组 实例化对象
points=new ArrayList<>();
lineTagsList = new ArrayList<>();
password = new StringBuilder();
selectedList= new ArrayList<>();
//获取xml的文本控件
alertTextView = findViewById(R.id.tv_alert);
//获取偏好设置对象
//key-Value Map
//文件的路径 mode
//mode:模式
//只能读
//
// SharedPreferences sp= getSharedPreferences("abc",MODE_PRIVATE);
// String result =sp.getString("pwd",null);
// System.out.println(result);
//如果需要存储数据 必须获取Editor对象
/*
SharedPreferences.Editor editor = sp.edit();
editor.putString("pwd","123");
//保存
editor.commit(); //立刻保存
//editor.apply(); //异步 让一个线程处理保存 不是马上
*/
//查找偏好设置里面是否有保存的密码
SharedPreferences sp = getSharedPreferences("password",MODE_PRIVATE);
//获取pwd密码
orgPassword = sp.getString("pw",null);
if(orgPassword==null){
alertTextView.setText("请设置密码图案");
}else {
alertTextView.setText("请绘制密码图案");
}
}
}
网友评论