1.Xml⽂文件设置容器器为RelativeLayout,同时添加id:
<?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">
2.添加⼦子控件
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/main_bg" />
<!-- 9个点的背景图片-->
<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"
/>
3.监听窗⼝口focus状态改变->此刻整个容器器的尺⼨寸已经计算完毕:
4.准备工作
//定义一个数组 保存每个点的控件
ArrayList<ImageView> dotsList;
ArrayList<Integer> lineTagList;
ArrayList<ImageView> selectedList;
int tag;
//保存上一次被点亮的点的对象
ImageView lastSelectedDot;
//记录滑动的密码
StringBuilder password;
//保存原始密码
String orgPassword;
//提示的文本视图
TextView alertTextView;
//保存第一次输入的密码
String firstPassword;
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//判断是否已经显示
if (hasFocus) {
//获取容器
RelativeLayout r1 = findViewById(R.id.root_layout);
//获取背景视图的尺寸
ImageView iv = findViewById(R.id.opview);
//获取x和y的坐标
int x = iv.getLeft();
int y = iv.getTop();
5.将素材显示在容器里,以及设置对应的tag值
(1)
tag = 1;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//创建 用于显示点的视图
ImageView dotView = new ImageView(this);
//设置对应的tag
dotView.setTag(tag);
lineTagList.add(tag);
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);
//将子控件添加到容器中
r1.addView(dotView, params);
//将这个控件添加到数组里面
dotsList.add(dotView);
}
}
(2)
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);
lineTagList.add(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);
r1.addView(lineView, params);
System.out.println(lineView.getTag());
}
tag += 11;
}
(3)
tag = 14;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
//创建一个视图同于显示线
ImageView lineView = new ImageView(this);
lineView.setVisibility(View.INVISIBLE);
//设置图片
lineView.setBackgroundResource(R.drawable.normal_highlight2);
lineView.setTag(tag);
lineTagList.add(tag);
tag += 11;
//创建布局尺寸
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);
r1.addView(lineView, params);
}
}
(4)
//创建右下斜线
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
//创建一个视图同于显示线
ImageView rlineView = new ImageView(this);
rlineView.setVisibility(View.INVISIBLE);
//设置图片
rlineView.setBackgroundResource(R.drawable.normal_highlight3);
//创建布局尺寸
rlineView.setTag(rtag);
lineTagList.add(rtag);
rtag += 11;
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);
r1.addView(rlineView, params);
}
rtag += 11;
}
(5)
int lTag = 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.setBackgroundResource(R.drawable.normal_highlight4);
llineView.setTag(lTag);
lineTagList.add(lTag);
lTag += 11;
//创建布局尺寸
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);
r1.addView(llineView, params);
}
lTag += 11;
}
}
6.触摸事件的处理:
@Override
public boolean onTouchEvent(MotionEvent event)
{
//获取事件的类型
int action = event.getAction();
//判断是什么类型
ImageView selectted;
float x;
float y;
switch (action) {
case MotionEvent.ACTION_DOWN:
//按下
//获取触摸点的坐标
x = event.getX();
y = event.getY();
//判断xy是不是在点的范围内
selectted = dotOfTouch(x, y);
//点亮
if (selectted != null) {
selectted.setVisibility(View.VISIBLE);
//记录当前这个点
lastSelectedDot = selectted;
//将tag值拼接到密码中
password.append(selectted.getTag());
//将点亮的点添加到数组中
selectedList.add(selectted);
}
break;
case MotionEvent.ACTION_MOVE:
//移动
//获取触摸点的坐标
x = event.getX();
y = event.getY();
//判断xy是不是在点的范围内
selectted = dotOfTouch(x, y);
//点亮
if (selectted != null) {
//判断是不是第一个点
if (lastSelectedDot == null) {
//第一个点
selectted.setVisibility(View.VISIBLE);
//将tag值拼接到密码中
password.append(selectted.getTag());
//将点亮的点添加到数组中
selectedList.add(selectted);
//记录
lastSelectedDot = selectted;
} else {
//不是第一个点
//获取上一个点和当前点的tag组成的线的tag
int llTag = (Integer) lastSelectedDot.getTag();
int cTag = (Integer) selectted.getTag();
int lineTag = llTag > cTag ? cTag * 10 + llTag : llTag * 10 + cTag;
//判断这个线是否存在
if (lineTagList.contains(lineTag)) {
//线存在
//点亮点
selectted.setVisibility(View.VISIBLE);
//将tag值拼接到密码中
password.append(selectted.getTag());
//将点亮的点添加到数组中
selectedList.add(selectted);
//获取容器对象
RelativeLayout rl = findViewById(R.id.root_layout);
//通过tag查找子控件
ImageView iv = rl.findViewWithTag(lineTag);
//点亮线
iv.setVisibility(View.VISIBLE);
//将点亮的线添加到数组中
selectedList.add(iv);
//记录这个点
lastSelectedDot = selectted;
} else {
}
}
}
break;
case MotionEvent.ACTION_UP:
//离开
// 1.绘制密码 和原始密码比较
// 2.设置密码 第一次
//3.设置密码 第二次
if(orgPassword!=null){
//有密码了
if(password.toString().equals(orgPassword)){
alertTextView.setText("解锁密码成功");
}else{
alertTextView.setText("解锁密码失败");
}
}else{
//设置密码
//判断是第一次还是第二次确认密码
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("hsl",firstPassword);
editor.commit();
}else{
//设置失败
alertTextView.setText("两次密码不一致,请重新设置");
firstPassword=null;
}
}
}
claen();
break;
default:
break;
}
return true;
}
//清空
public void claen() {
password.setLength(0);
//隐藏所有选中的选图 点线
//遍历所有选中的视图 点 线
for (ImageView iv : selectedList) {
iv.setVisibility(View.INVISIBLE);
}
//清空数组
selectedList.clear();
}
//写一个方法处理 判断 触摸点是否在某个控件内部
public ImageView dotOfTouch(float x, float y) {
/*1.让触摸点 切换到控件的父视图中
//计算标题栏或者状态栏的距离
Point p=new Point();
getWindowManager().getDefaultDisplay().getSize(p);
//获取容器本身的高度
RelativeLayout rl=findViewById(R.id.root_layout);
//计算状态栏的高度
float padding=p.y-rl.getHeight();
*/
/*2.让控件切换到屏幕坐标系
ImageView firt=dotsList.get(0);
int[] loc=new int[2];
firt.getLocationOnScreen(loc);
System.out.println("相对屏幕:"+loc[1]);
System.out.println("相对容器"+firt.getY());
*/
//遍历数组
//获取第一个点
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;
}
7.重写oncreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//准备好数组 实例化对象
dotsList = new ArrayList<>();
lineTagList = new ArrayList<>();
password = new StringBuilder();
selectedList = new ArrayList<>();
alertTextView = findViewById(R.id.tv_alert);
/**
//获取偏好设置对象 整个程序共享 单例
//name:文件的路径
//mode:模式
//只能读
SharedPreferences sp = getSharedPreferences("abc1",MODE_PRIVATE);
//如果需要存储数据 必须获取Editor对象
SharedPreferences.Editor editor=sp.edit();
editor.putString("pwd","123");
//保存
editor.commit();//立刻保存
editor.apply();//异步 让一个线程运行 不是马上
*/
// 查找偏好设置里面是否有保存的密码
SharedPreferences sp=getSharedPreferences("password",MODE_PRIVATE);
//获取hsl对应的密码
orgPassword=sp.getString("hsl",null);
if(orgPassword==null){
alertTextView.setText("请设置密码图案");
}else{
alertTextView.setText("请绘制密码图案");
}
}
}
心得体会
休息够了又该回到学习中了,重温了一下之前学的,收获还不错,继续努力吧