3.2安卓触摸事件

一、安卓触摸事件概述

1、触摸分类

(1)单点触摸

  • 单点触控,只能识别和支持每次一个手指的触控、点击,若同时有两个以上的点被触碰,就不能做出正确反应。很多医院、图书馆等的大厅都有这种触控技术的电脑,支持触摸屏的手机、MP3、数码相机也多采用这种单点触控技术。

(2)多点触摸

  • 多点触控(又称多重触控、多点感应、多重感应,英文Multitouch或Multi-Touch)是采用人机交互技术与硬件设备共同实现的技术,能在没有传统输入设备(如鼠标、键盘等)。下进行计算机的人机交互操作。多点触摸技术,能构成一个触摸屏(屏幕,桌面,墙壁等)或触控板,都能够同时接受来自屏幕上多个点进行计算机的人机交互操作。

2、触摸动作

动作常量
按下MotionEvent.ACTION_DOWN
移动MotionEvent.ACTION_MOVE
放开MotionEvent.ACTION_UP

3、触摸监听器

  • 触摸监听器 - onTouchListener - 接口

4、触摸方法

  • 在onTouch()抽象 方法里,我们可以根据不同动作编写不同事件处理代码

5、触点个数与坐标

  • 通过MotionEvent对象的getX()getY()方法可以获得触摸点的坐标。如果是多点触摸,通过getPointerCount()获取触点个数,然后通过getX(pointerIndex)getY(pointerIndex)获得某个触点的坐标。

6、安卓触摸事件处理机制

  • 触摸事件从view树的根节点开始一直传递到最下层,直到某个onTouchEvent()接收处理此事件。每个部分对触摸事件的处理过程如下:
  • Activity的处理过程: Activity.dispatchTouchEvent()最先被调用,其作用是调用RootView(通常是一个ViewGroup)的dispatchTouchEvent(),即负责分发事件。ViewGroup中的dispatch会调用其他孩子的dispatchTouchEvent()。注意:Activity中的onTouchEvent()是整个View的触摸事件传递链条的终点,不过前提是整个过程中没有view的touchEvent对此事件感兴趣。
  • View的处理过程: 检查是否有TouchListener()注册在这个View中,如果有则查看其是否想要消费此次事件,如果不消费事件,那么接下来该View的onTouchEvent()就要被调用了,如果未返回true,事件就会返回视图树的上一层。
  • ViewGroup的处理过程: 根据触摸发生的位置来判断哪些孩子可能会触发触摸事件,如果有重叠部分则按照被加入到ViewGroup中顺序的逆序来依次处理。ViewGroup可以引发一个中断(onInterceptTouchEvent())来强制把事件交给自己处理,当子视图的事件被剥夺时,子视图会收到ACTION_CANCEL事件,子视图可以用requestDisallowTouchIntercept()方法来屏蔽这个事件。
  • 由此可见,Touch事件是层层向下传递的,如果某个视图接收了此事件则接下来的视图就无法再次接收,但ViewGroup可以强制从子视图手中剥夺一个触摸事件。

二、案例演示:通过单点触摸移动米老鼠

1、创建安卓应用

在这里插入图片描述

2、准备图片素材

在这里插入图片描述

3、字符串资源文件

<resources>
    <string name="app_name">通过触摸移动米老鼠</string>
</resources>

4、主布局资源文件

  • 将约束布局改成线性布局,再添加一个图像控件显示米老鼠
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:id="@+id/root"
    android:background="@drawable/background"
    android:orientation="vertical"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <ImageView
        android:id="@+id/iv_mickey"
        android:layout_width="100dp"
        android:layout_height="120dp"
        android:scaleType="fitXY"
        android:src="@drawable/mikey"
        />


</LinearLayout>
  • 预览效果
    在这里插入图片描述

5、主界面类实现功能

  • 声明变量和常量
    在这里插入图片描述
  • 通过资源标识符获取控件实例
    在这里插入图片描述
  • 让根布局获取焦点
    在这里插入图片描述
  • 获取米老鼠图像控件的布局参数
    在这里插入图片描述
  • 给线性根布局注册触摸监听器

在这里插入图片描述

  • 完整代码
package net.ls.movemickeybytouch;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    private ImageView ivMickey; //米老鼠图像控件
    private LinearLayout root; //线性根布局
    private LinearLayout.LayoutParams layoutParams; //布局参数
    private static final String TAG = "move_mickey_by_touch"; //标记常量

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        root=findViewById(R.id.root);
        ivmickey = findViewById(R.id.iv_mickey);
        //让根布局成为焦点
        root.setFocusable(true);
        root.requestFocus();
        //获取米老鼠图像控件的布局参数
        layoutParams = (LinearLayout.LayoutParams) ivmickey.getLayoutParams();
        // 给线性根布局注册触摸监听器,实现监听器接口,编写触摸事件代码
        root.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN://0,触点按下
                        Log.d(TAG,"ACTION_DOWN("+event.getX()+","+event.getY()+")");
                        break;
                    case MotionEvent.ACTION_MOVE://2,触点移动
                        Log.d(TAG,"ACTION_MOVE("+event.getX()+","+event.getY()+")");
                        break;
                    case MotionEvent.ACTION_UP://1,触点放开
                        Log.d(TAG,"ACTION_UP("+event.getX()+","+event.getY()+")");
                        break;
                }
               // 根据变化的触点坐标来更新米老鼠图像控件的布局参数
                layoutParams.leftMargin = (int) event.getX();
                layoutParams.topMargin = (int) event.getY();
                // 重新设置米老鼠图像控件的布局参数
                ivMickey.setLayoutParams(layoutParams);

                return true; // 设置为true,三个事件:down-->move-->up才会依次执行
            }
        });
    }
}
  • 查看效果
    在这里插入图片描述

6、优化主界面类

  • 以上代码可完成移动米老鼠的任务,但触摸中心点在左上角,现在优化代码让触摸点在米老鼠中心
  • 不采用图像控件的布局参数,直接调用图像控件的setX()setY()方法,分别传入触点横坐标event.getX()和纵坐标event.getY(),如果希望触点在米老鼠控件中央,那么分别传入event.getX() - ivMickey.getWidth() / 2event.getY() - ivMickey.getHeight() / 2
    在这里插入图片描述
package net.ls.movemickeybytouch;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    private ImageView ivmickey; //米老鼠图像控件
    private LinearLayout root; //线性根布局
    private LinearLayout.LayoutParams layoutParams; //布局参数
    private static final String TAG = "move_mickey_by_touch"; //标记常量

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        root=findViewById(R.id.root);
        ivmickey = findViewById(R.id.iv_mickey);
        //让根布局成为焦点
        root.setFocusable(true);
        root.requestFocus();
        //获取米老鼠图像控件的布局参数
        layoutParams = (LinearLayout.LayoutParams) ivmickey.getLayoutParams();
        // 给线性根布局注册触摸监听器,实现监听器接口,编写触摸事件代码
        root.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN://0,触点按下
                        Log.d(TAG,"ACTION_DOWN("+event.getX()+","+event.getY()+")");
                        break;
                    case MotionEvent.ACTION_MOVE://2,触点移动
                        Log.d(TAG,"ACTION_MOVE("+event.getX()+","+event.getY()+")");
                        break;
                    case MotionEvent.ACTION_UP://1,触点放开
                        Log.d(TAG,"ACTION_UP("+event.getX()+","+event.getY()+")");
                        break;
                }
                //设置米老鼠图像控件坐标
                ivmickey.setX(event.getX()-ivmickey.getWidth()/2);
                ivmickey.setY(event.getY()-ivmickey.getHeight()/2);
                return true;
            }
        });
    }
}

7、效果

在这里插入图片描述

三、案例演示:通过多点触摸缩放米老鼠

1、创建安卓应用

  • 基于Empty Activity模板创建安卓应用 - ZoomMickeyByTouch
    在这里插入图片描述

2、准备图片素材

在这里插入图片描述

3、字符串资源文件

在这里插入图片描述

4、主布局资源文件

在这里插入图片描述

  • 将约束布局改成线性布局,再添加一个图像控件显示米老鼠
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/root"
    android:background="@drawable/background"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <ImageView
        android:id="@+id/iv_mickey"
        android:layout_width="100dp"
        android:layout_height="120dp"
        android:src="@drawable/mickey"/>


</LinearLayout>
  • 预览效果
    在这里插入图片描述

5、主界面类实现功能

  • 声明变量
    在这里插入图片描述
  • 通过资源标识符获取控件实例,让根布局获取焦点,让根布局获取焦点
    在这里插入图片描述
  • 给根布局注册触摸监听器
    在这里插入图片描述
  • 完整代码
package net.ls.zoommickeybytouch;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    private LinearLayout root;
    private ImageView ivMickey;
    private float x1,y1;//第一个触点的坐标
    private float x2,y2;//第二个触点的坐标
    private float nextX1,nextY1;//第一个触点的下一次坐标
    private float nextX2,nextY2;//第二个触点的下一次坐标
    private float distance; //两个触点间的距离
    private float nextDistance;//两个触点的下一次距离
    private LinearLayout.LayoutParams layoutParams;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        root = findViewById(R.id.root);
        ivMickey = findViewById(R.id.iv_mickey);
        root.setFocusable(true);
        root.requestFocus();
        layoutParams = (LinearLayout.LayoutParams) ivMickey.getLayoutParams();
        //给根布局注册触摸监听器,实现触摸监听器接口,编写触摸事件方法
        root.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //判断触点个数
                if (event.getPointerCount()==1){ //单点触摸 - 移动米老鼠
                    layoutParams.leftMargin = (int)(event.getX() - ivMickey.getWidth()/2);
                    layoutParams.topMargin = (int)(event.getY() - ivMickey.getHeight()/2);
                }else if (event.getPointerCount()==2){ //两点触摸 - 缩放米老鼠
                    //判断触点动作
                    switch (event.getAction()){
                        case MotionEvent.ACTION_DOWN:
                            //获取第一个触点的坐标
                            x1 = event.getX(0);
                            y1 = event.getY(0);
                            //获取第二个触点的坐标
                            x2 = event.getX(1);
                            x2 = event.getY(1);
                            distance =(float) Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
                            break;
                        case MotionEvent.ACTION_MOVE:
                            //获取第一个触点下一次的坐标
                            nextX1 = event.getX(0);
                            nextY1 = event.getY(0);
                            //获取第二个触点下一次的坐标
                            nextX2 = event.getX(1);
                            nextY2 = event.getY(1);
                            //计算两个触点的下一次距离
                            nextDistance = (float) Math.sqrt((nextX1-nextX2)*(nextX1-nextX2)+(nextY1-nextY2)*(nextY1-nextY2));
                            break;
                        case MotionEvent.ACTION_UP:
                            break;
                    }
                    //修改米老鼠图像控件的布局参数
                    if (nextDistance>distance){
                        if (layoutParams.width<1000){
                        layoutParams.width  = (int) (layoutParams.width*1.05);
                        layoutParams.height = (int) (layoutParams.height*1.05);}
                    } else {
                        if (layoutParams.width>10) {
                            layoutParams.width = (int) (layoutParams.width / 1.05);
                            layoutParams.height = (int) (layoutParams.height / 1.05);
                        }
                    }
                    //第一个触点坐标进行迭代
                    x1 = nextX1;
                    y1 = nextY1;
                    x2 = nextX2;
                    y2 = nextY2;
                    distance=(float) Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

                }
                ivMickey.setLayoutParams(layoutParams);

                return true;
            }
        });
    }
}

6、运行程序,查看结果

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio是一款由Google开发的集成开发环境(IDE),用于开发Android应用程序。它提供了丰富的工具和功能,使开发者能够轻松地创建、测试和调试Android应用。 在Android Studio的技术路线中,主要包括以下几个方面: 1. Java语言基础:Android应用程序主要使用Java语言进行开发,因此熟悉Java语言的基本语法和特性是必要的。开发者需要了解面向对象编程、异常处理、集合框架等Java的核心概念。 2. Android框架:Android框架是构建Android应用程序的基础,它提供了一系列的API和组件,用于处理用户界面、数据存储、网络通信等功能。开发者需要学习Android框架的各个组件,如Activity、Fragment、Service、BroadcastReceiver等,并了解它们之间的交互方式。 3. XML布局:Android应用程序的用户界面通常使用XML文件进行布局。开发者需要学习XML的基本语法和布局方式,掌握如何使用XML文件定义界面元素和布局结构。 4. Gradle构建系统:Android Studio使用Gradle作为项目的构建系统。开发者需要学习Gradle的基本概念和配置方式,了解如何管理项目依赖、打包发布应用等。 5. 调试和测试:Android Studio提供了强大的调试和测试工具,开发者需要学习如何使用这些工具来调试应用程序、查找问题和进行性能优化。 6. 版本控制:Android Studio集成了版本控制系统,如Git,方便开发者进行代码管理和团队协作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值