Android开发第三天

onTouch事件——手势解锁

目录

  1. 事件处理
  2. 重写触摸回调事件onTouch
  3. onTouch实例

详解

  1. 事件处理

1.监听
1.事件源:事件在哪里发生的
2.监听者:发生后由谁来处理 注册
3.事件:点击,长按,旋转

2.回调
自己处理自己的事件
1.触摸事件MotionEvent
手滑动控件跟着

  1. 重写触摸回调事件onTouch

返回值表示这个事件是否被处理
true:事件已经处理
false:自己不消费 事件还要继续往下传
系统自动将事件包装为MotionEvent类
用户可以获取事件的行为:getAction
ACTION_DOWN ACTION_MOVE ACTION_UP ACTION_CANCEL
获取触摸点的坐标:getX getY

  1. onTouch实例
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());
        //计算界面和屏幕之间的距离
        float padding=p.y-rl.getHeight();
        if (action==MotionEvent.ACTION_DOWN){
            //按下
            //获取触摸点x,y坐标
            float x=event.getX();//相对于屏幕
            //event.getRawX();//相对于父视图
            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){
            //移动
            //获取触摸点x,y坐标
            float x=event.getX();//相对于屏幕
            //event.getRawX();//相对于父视图
            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){
            //离开

        }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;
    }
}

练习——手势解锁(续)

<?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个点的背景图⽚-->
 <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{
 //定义⼀个数组 保存每个点的控件
 ArrayList<ImageView> dotsList;
 ArrayList<Integer> lineTagsList;
 ArrayList<ImageView> selectedList;
 int tag;
 //保存上⼀次被点亮的点的对象
 ImageView lastSelectedDot;
 //记录滑动的密码
 StringBuilder password;
 //保存原始密码
 String orgPassword;
 //保存第⼀次输⼊的密码
 String firstPassword;
 //提示的⽂本视图
 TextView alertTextView;
 @Override
 public void onWindowFocusChanged(boolean hasFocus) {
 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();
 //获取屏幕密度
 float scale = getResources().getDisplayMetrics().density;
 //创建横线 6条
 //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);
 lineView.setBackgroundResource(R.drawable.normal_highlight1);
 lineView.setVisibility(View.INVISIBLE);
 lineView.setTag(tag);
 lineTagsList.add(tag);//保存线的tag值
 tag += 11; //同⼀⾏相差11
 //创建布局参数
 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;
 }
 //创建竖线 4条
 //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);
 lineView.setBackgroundResource(R.drawable.normal_highlight2);
 lineView.setVisibility(View.INVISIBLE);
 lineView.setTag(tag);
 lineTagsList.add(tag);//保存线的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);
 rl.addView(lineView, params);
 }
 }
 //创建斜线
 //左斜
 // 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++) {
 //创建⼀个视图⽤于显示线
 ImageView rLineView = new ImageView(this);
 rLineView.setTag(rTag);
 lineTagsList.add(rTag);//保存线的tag值
 rTag += 11;
 //设置图⽚
 rLineView.setBackgroundResource(R.drawable.normal_highlight3);
 //创建布局参数
 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;
 }
 //创建9个点
 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);
 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.33*scale) + (int)(98.66*scale*j);
 params.topMargin = (int)(y + 162*scale) + (int)(98.66*scale*i);
 //将控件添加到容器中
 rl.addView(dotView, params);
 //将这个控件添加到数组
 dotsList.add(dotView);
 }
 }
 }
 }
 //监听触摸事件
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 //获取事件的类型
 int action = event.getAction();
 ImageView selected;
 float x;
 float y;
 //判断是什么事件
 switch (action){
 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 (lastSelectedDot == null){
 //第⼀个点
 selected.setVisibility(View.VISIBLE);
 //记录
 lastSelectedDot = selected;
 //将tag值拼接到密码中
 password.append(selected.getTag());
 //将点亮的点添加到数组中
 selectedList.add(selected);
 } else{
 //不是第⼀个点
 //获取上⼀个点和当前点的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);
 //将tag值拼接到密码中
 password.append(selected.getTag());
 //点亮这条线
 //获取容器对象
 RelativeLayout rl = findViewById(R.id.root_layout);
 //通过tag查找⼦控件
 ImageView iv = rl.findViewWithTag(lineTag);
 //点亮线
 iv.setVisibility(View.VISIBLE);
 //记录这个点
 lastSelectedDot = selected;
 //将点亮的点添加到数组中
 selectedList.add(selected);
 //将点亮的线添加到数组中
 selectedList.add(iv);
 }
 }
 }
 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("pwd",firstPassword);
 editor.commit();
 } else{
 //设置失败
 alertTextView.setText("两次密码不⼀致 请重新设置");
 firstPassword = null;
 }
 }
 }
 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){
 //计算状态栏或者标题栏的距离
 /*
 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("相对屏幕y:"+loc[1]);
 System.out.println("相对容器y:"+firt.getY());
 System.out.println("原本宽度:"+firt.getWidth());
 */
 //遍历数组
 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;
 }
/**
 * 安卓 在容器中添加的控件需要被window计算/测量
 * window -> viewGroup -> ⼦控件
 * 通常在onCreate、onStart、onResume⽆法获取到控件本身的尺⼨
 *
 * 所有的测量都是在另外⼀个线程操作
 * 如果想要获取控件的尺⼨
 */
 /**
 * Android数据存储4种
 * 1. sharedPreference 偏好设置
 * 2. file
 * 3. sqlite3
 * 4. network
 */
@Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 //准备好数组 实例化对象
 dotsList = new ArrayList<>();
 lineTagsList = new ArrayList<>();
 password = new StringBuilder();
 selectedList = new ArrayList<>();
 //获取xml的⽂本控件
 alertTextView = findViewById(R.id.tv_alert);
 //获取偏好设置对象 整个程序共享 单例
 //key-value Map
 //name:⽂件的路劲
 //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(); //异步 让⼀个线程处理保存 不是⻢上
 */
 //查找偏好设置⾥⾯是否有保存的密码pwd
 SharedPreferences sp = 
getSharedPreferences("password",MODE_PRIVATE);
 //获取pwd对应密码
 orgPassword = sp.getString("pwd",null);
 if (orgPassword == null){
 alertTextView.setText("请设置密码图案");
 }else{
 alertTextView.setText("请绘制密码图案");
 }
 }
 @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("竖屏");
 }
 }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容