onTouch事件——手勢(shì)解鎖
目錄
- 事件處理
- 重寫(xiě)觸摸回調(diào)事件onTouch
- onTouch實(shí)例
詳解
- 事件處理
1.監(jiān)聽(tīng)
1.事件源:事件在哪里發(fā)生的
2.監(jiān)聽(tīng)者:發(fā)生后由誰(shuí)來(lái)處理 注冊(cè)
3.事件:點(diǎn)擊嫉沽,長(zhǎng)按,旋轉(zhuǎn)
2.回調(diào)
自己處理自己的事件
1.觸摸事件MotionEvent
手滑動(dòng)控件跟著
- 重寫(xiě)觸摸回調(diào)事件onTouch
返回值表示這個(gè)事件是否被處理
true:事件已經(jīng)處理
false:自己不消費(fèi) 事件還要繼續(xù)往下傳
系統(tǒng)自動(dòng)將事件包裝為MotionEvent類(lèi)
用戶(hù)可以獲取事件的行為:getAction
ACTION_DOWN ACTION_MOVE ACTION_UP ACTION_CANCEL
獲取觸摸點(diǎn)的坐標(biāo):getX getY
- onTouch實(shí)例
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.graphics.Point;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends AppCompatActivity {
View redView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
redView=findViewById(R.id.view);
}
/* @Override
public boolean onTouchEvent(MotionEvent event) {
//檢查為什么事件
int action=event.getAction();
//獲取屏幕大小
Point p=new Point();
getWindowManager().getDefaultDisplay().getSize(p);
//System.out.println("屏幕高:"+p.y);
//獲取容器本身寬高
RelativeLayout rl=findViewById(R.id.root);
//System.out.println("容器高:"+rl.getHeight());
//計(jì)算界面和屏幕之間的距離
float padding=p.y-rl.getHeight();
if (action==MotionEvent.ACTION_DOWN){
//按下
//獲取觸摸點(diǎn)x途样,y坐標(biāo)
float x=event.getX();//相對(duì)于屏幕
//event.getRawX();//相對(duì)于父視圖
float y=event.getY()+padding;
//改變控件的位置
redView.setX(x-(float)(redView.getWidth()*0.5));
redView.setY(y-(float)(redView.getHeight()*0.5));
}else if (action==MotionEvent.ACTION_MOVE){
//移動(dòng)
//獲取觸摸點(diǎn)x辖佣,y坐標(biāo)
float x=event.getX();//相對(duì)于屏幕
//event.getRawX();//相對(duì)于父視圖
float y=event.getY()-padding;
//改變控件的位置
redView.setX(x-(float)(redView.getWidth()*0.5));
redView.setY(y-(float)(redView.getHeight()*0.5));
}else if (action==MotionEvent.ACTION_UP){
//離開(kāi)
}else {
}
return true;
}
*/
//查找
@Override
public boolean onTouchEvent(MotionEvent event) {
//更改控件顏色
//redView.setBackgroundColor(Color.GREEN);
RelativeLayout rl=findViewById(R.id.root);
View iv= rl.findViewWithTag("1");
iv.setBackgroundColor(Color.GREEN);
return true;
}
}
練習(xí)——手勢(shì)解鎖(續(xù))
<?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:src="@drawable/main_bg"
android:scaleType="fitXY"
/>
<!--9個(gè)點(diǎn)的背景圖?-->
<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>
public class MainActivity extends AppCompatActivity{
//定義?個(gè)數(shù)組 保存每個(gè)點(diǎn)的控件
ArrayList<ImageView> dotsList;
ArrayList<Integer> lineTagsList;
ArrayList<ImageView> selectedList;
int tag;
//保存上?次被點(diǎn)亮的點(diǎn)的對(duì)象
ImageView lastSelectedDot;
//記錄滑動(dòng)的密碼
StringBuilder password;
//保存原始密碼
String orgPassword;
//保存第?次輸?的密碼
String firstPassword;
//提示的?本視圖
TextView alertTextView;
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//判斷是否已經(jīng)顯示
if (hasFocus){
//獲取容器
RelativeLayout rl = findViewById(R.id.root_layout);
//獲取背景視圖
ImageView iv = findViewById(R.id.opView);
//獲取x 和 y坐標(biāo)
int x = iv.getLeft();
int y = iv.getTop();
//獲取屏幕密度
float scale = getResources().getDisplayMetrics().density;
//創(chuàng)建橫線 6條
//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);
lineView.setBackgroundResource(R.drawable.normal_highlight1);
lineView.setVisibility(View.INVISIBLE);
lineView.setTag(tag);
lineTagsList.add(tag);//保存線的tag值
tag += 11; //同??相差11
//創(chuàng)建布局參數(shù)
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);
}
//換?? 相差22
tag += 11;
}
//創(chuàng)建豎線 4條
//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);
lineView.setBackgroundResource(R.drawable.normal_highlight2);
lineView.setVisibility(View.INVISIBLE);
lineView.setTag(tag);
lineTagsList.add(tag);//保存線的tag值
tag += 11;
//創(chuàng)建布局參數(shù)
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);
}
}
//創(chuàng)建斜線
//左斜
// 24 35
// 57 68
// 右斜
// 15 26
// 48 59
tag = 24;
int rTag = 15;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
//創(chuàng)建?個(gè)視圖?于顯示線
ImageView rLineView = new ImageView(this);
rLineView.setTag(rTag);
lineTagsList.add(rTag);//保存線的tag值
rTag += 11;
//設(shè)置圖?
rLineView.setBackgroundResource(R.drawable.normal_highlight3);
//創(chuàng)建布局參數(shù)
rLineView.setVisibility(View.INVISIBLE);
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(rLineView, params);
ImageView lLineView = new ImageView(this);
lLineView.setTag(tag);
lineTagsList.add(tag);//保存線的tag值
tag += 11;
lLineView.setVisibility(View.INVISIBLE);
lLineView.setBackgroundResource(R.drawable.normal_highlight4);
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);
}
tag += 11;
rTag += 11;
}
//創(chuàng)建9個(gè)點(diǎn)
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);;
//設(shè)置對(duì)應(yīng)的tag值
dotView.setTag(tag);
tag++;
//隱藏視圖
dotView.setVisibility(View.INVISIBLE);
//顯示對(duì)應(yīng)的圖?
dotView.setBackgroundResource(R.drawable.selected_dot);
//創(chuàng)建控件的尺?
RelativeLayout.LayoutParams params = new
RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int)(x + 35.33*scale) + (int)(98.66*scale*j);
params.topMargin = (int)(y + 162*scale) + (int)(98.66*scale*i);
//將控件添加到容器中
rl.addView(dotView, params);
//將這個(gè)控件添加到數(shù)組
dotsList.add(dotView);
}
}
}
}
//監(jiān)聽(tīng)觸摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
//獲取事件的類(lèi)型
int action = event.getAction();
ImageView selected;
float x;
float y;
//判斷是什么事件
switch (action){
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);
if (selected != null) {
//點(diǎn)亮
selected.setVisibility(View.VISIBLE);
//記錄當(dāng)前這個(gè)點(diǎn)
lastSelectedDot = selected;
//將tag值拼接到密碼中
password.append(selected.getTag());
//將點(diǎn)亮的點(diǎn)添加到數(shù)組中
selectedList.add(selected);
}
break;
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);
if (selected != null) {
//判斷這個(gè)點(diǎn)是不是第?個(gè)點(diǎn)
if (lastSelectedDot == null){
//第?個(gè)點(diǎn)
selected.setVisibility(View.VISIBLE);
//記錄
lastSelectedDot = selected;
//將tag值拼接到密碼中
password.append(selected.getTag());
//將點(diǎn)亮的點(diǎn)添加到數(shù)組中
selectedList.add(selected);
} else{
//不是第?個(gè)點(diǎn)
//獲取上?個(gè)點(diǎn)和當(dāng)前點(diǎn)的tag
int lTag = (Integer) lastSelectedDot.getTag();
int cTag = (Integer) selected.getTag();
//獲取兩個(gè)線的tag值 small * 10 + big
int lineTag = lTag > cTag ? cTag*10+lTag: lTag*10+cTag;
//判斷這條線是否存在
if (lineTagsList.contains(lineTag)){
//線存在
//點(diǎn)亮點(diǎn)
selected.setVisibility(View.VISIBLE);
//將tag值拼接到密碼中
password.append(selected.getTag());
//點(diǎn)亮這條線
//獲取容器對(duì)象
RelativeLayout rl = findViewById(R.id.root_layout);
//通過(guò)tag查找?控件
ImageView iv = rl.findViewWithTag(lineTag);
//點(diǎn)亮線
iv.setVisibility(View.VISIBLE);
//記錄這個(gè)點(diǎn)
lastSelectedDot = selected;
//將點(diǎn)亮的點(diǎn)添加到數(shù)組中
selectedList.add(selected);
//將點(diǎn)亮的線添加到數(shù)組中
selectedList.add(iv);
}
}
}
break;
case MotionEvent.ACTION_UP:
//離開(kāi)
// 1.繪制密碼 和原始密碼?較
// 2.設(shè)置密碼 第?次
// 3.設(shè)置密碼 第?次
if (orgPassword != null){
//有密碼了
if (password.toString().equals(orgPassword)){
alertTextView.setText("解鎖密碼成功");
} else{
alertTextView.setText("解鎖密碼失敗");
}
} else{
//設(shè)置密碼
//判斷是第?次還是第?次確認(rèn)密碼
if (firstPassword == null){
//設(shè)置密碼的第?次
firstPassword = password.toString();
//提示確認(rèn)密碼
alertTextView.setText("請(qǐng)確認(rèn)密碼圖案");
} else{
//第?次確認(rèn)密碼
//判斷兩次是否?致
if (firstPassword.equals(password.toString())){
//設(shè)置成功
alertTextView.setText("設(shè)置密碼成功");
//保存密碼
SharedPreferences sp = getSharedPreferences("password",0);
SharedPreferences.Editor editor = sp.edit();
editor.putString("pwd",firstPassword);
editor.commit();
} else{
//設(shè)置失敗
alertTextView.setText("兩次密碼不?致 請(qǐng)重新設(shè)置");
firstPassword = null;
}
}
}
clean();
break;
default:
break;
}
return true;
}
//清空
public void clean(){
password.setLength(0);
//隱藏所有選中的視圖 點(diǎn) 線
for (ImageView iv:selectedList){
iv.setVisibility(View.INVISIBLE);
}
//清空數(shù)組
selectedList.clear();
}
//寫(xiě)?個(gè)?法 處理 判斷觸摸點(diǎn)是否在某個(gè)控件內(nèi)部
public ImageView dotOfTouch(float x, float y){
//計(jì)算狀態(tài)欄或者標(biāo)題欄的距離
/*
1. 讓觸摸點(diǎn) 切換到控件的?視圖中
Point p = new Point();
getWindowManager().getDefaultDisplay().getSize(p);
//獲取容器本身的寬?
RelativeLayout rl = findViewById(R.id.root_layout);
//計(jì)算狀態(tài)欄的?度
float padding = p.y - rl.getHeight();
*/
/*
//2.讓控件切換到屏幕坐標(biāo)系
ImageView firt = dotsList.get(0);
int[] loc = new int[2];
firt.getLocationOnScreen(loc);
System.out.println("相對(duì)屏幕y:"+loc[1]);
System.out.println("相對(duì)容器y:"+firt.getY());
System.out.println("原本寬度:"+firt.getWidth());
*/
//遍歷數(shù)組
for (ImageView dot:dotsList){
//獲取這個(gè)dot相對(duì)于屏幕的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();
//判斷這個(gè)點(diǎn)是否在這個(gè)范圍內(nèi)
if ((x <= r && x >= dx) &&
(y <= b && y >= dy)){
return dot;
}
}
return null;
}
/**
* 安卓 在容器中添加的控件需要被window計(jì)算/測(cè)量
* window -> viewGroup -> ?控件
* 通常在onCreate擅腰、onStart、onResume?法獲取到控件本身的尺?
*
* 所有的測(cè)量都是在另外?個(gè)線程操作
* 如果想要獲取控件的尺?
*/
/**
* Android數(shù)據(jù)存儲(chǔ)4種
* 1. sharedPreference 偏好設(shè)置
* 2. file
* 3. sqlite3
* 4. network
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//準(zhǔn)備好數(shù)組 實(shí)例化對(duì)象
dotsList = new ArrayList<>();
lineTagsList = new ArrayList<>();
password = new StringBuilder();
selectedList = new ArrayList<>();
//獲取xml的?本控件
alertTextView = findViewById(R.id.tv_alert);
//獲取偏好設(shè)置對(duì)象 整個(gè)程序共享 單例
//key-value Map
//name:?件的路勁
//mode:模式
//只能讀
/*
SharedPreferences sp = getSharedPreferences("abc",MODE_PRIVATE);
String result = sp.getString("pwd",null);
System.out.println(result);
*/
/*
//如果需要存儲(chǔ)數(shù)據(jù) 必須獲取Editor對(duì)象
SharedPreferences.Editor editor = sp.edit();
editor.putString("pwd", "123");
//保存
editor.commit(); //?刻保存
//editor.apply(); //異步 讓?個(gè)線程處理保存 不是?上
*/
//查找偏好設(shè)置??是否有保存的密碼pwd
SharedPreferences sp =
getSharedPreferences("password",MODE_PRIVATE);
//獲取pwd對(duì)應(yīng)密碼
orgPassword = sp.getString("pwd",null);
if (orgPassword == null){
alertTextView.setText("請(qǐng)?jiān)O(shè)置密碼圖案");
}else{
alertTextView.setText("請(qǐng)繪制密碼圖案");
}
}
@Override
protected void onResume() {
super.onResume();
Point p = new Point();
getWindowManager().getDefaultDisplay().getSize(p);
float w = p.x;
float h = p.y;
if (w > h){
System.out.println("橫屏");
} else{
System.out.println("豎屏");
}
}
}