Android实现手势监听_android监听全局手势-程序员宅基地

技术标签: Android进阶  

在Android系统中,每一次手势交互都会依照以下顺序执行。

       1. 接触接触屏一刹那,触发一个MotionEvent事件。
       2. 该事件被OnTouchListener监听,在其onTouch()方法里获得该MotionEvent对象。
       3. 通过GestureDetector(手势识别器)转发次MotionEvent对象至OnGestureListener。
       4. OnGestureListener获得该对象,听根据该对象封装的的信息,做出合适的反馈。

        在Android中,是由GestureDetector类来负责手势的检测,每一个GestureDetector类的实例都代表一个手势监听器。在创建手势监听器时需要一个类OnGestureListener例。在OnGestureListerner接口里面,有以下事件处理的方法可供调用:

boolean onDown(MotionEvent e):当用户在屏幕上按下时会触发该方法,但在移动或抬起手指时不会触发。
void onShowPress(MotionEvent e):当用户在屏幕上按下,并且既没有移动有没有抬起手指时,会触发该方法。一般通过该方法告知用户他们的动作已经被识别到了,你可以 高亮某个元素来提醒他们。
boolean onSingleTapUp(MotionEvent e);:当用户在屏幕上轻击时(通常是指点击屏幕的时间很短)会触发该方法。
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);:当用户在屏幕上发起滚动的手势时会触发该方法。参数中的e1指第一个按下开 始滚动的动作事件,e2指触发当前这个方法的移动动作的事件,distanceX和distanceY则分别触发onScroll方法期间的X、Y轴上的滚动距离,而不是指e1和e2两个事件发生直接的距离。
void onLongPress(MotionEvent e);:当用户在屏幕上持续地长按时会触发该方法。
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);:当用户在屏幕上持续地按下并且有“抛”的动作时,会触发该方法。对于该事件的理解,你可以体会一下按住一个图标然后把它扔到某个地方的感觉。参数中的e1指第一个按下的动作事件,e2指触发当前这个方法的“猛扔”动作的事件,velocityX和velocityY则分别触发onFling方法期间X、Y轴上的移动速度。

除了以上还有OnDoubleTapListener这个接口,它是双击事件的一个监听器,它包含了下面这些方法。
boolean onSingleTapConfirmed(MotionEvent e):当用户在屏幕上单击是会触发此方法,与上面的onSingleTapUp方法不同的地方在于,该方法只会在监听器确定了用户在第一次单击后不会触发双击事件时才会被触发。
boolean onDoubleTap(MotionEvent e):当用户在屏幕上双击时会触发此方法。这里的按下动作事件指的时双击中的第一次触击。
boolean onDoubleTapEvent(MotionEvent e):在双击事件发生时会触发此方法,包括了按下、移动和抬起事件。

下面的Demo实现图片的切换:

public class Two_activity extends AppCompatActivity implements View.OnTouchListener, GestureDetector.OnGestureListener {
    private GestureDetectorCompat detector;
    int[] girls = new int[]{R.mipmap.pic3, R.mipmap.pic6, R.mipmap.pic7, R.mipmap.pic8, R.mipmap.timg, R.mipmap.timg2};
    private int index = 0;
    private ImageView image;

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

        detector = new GestureDetectorCompat(this,this);
        image = (ImageView) findViewById(R.id.image);
        image.setImageResource(girls[index]);
        image.setOnTouchListener(this);
        image.setLongClickable(true);
        detector.setIsLongpressEnabled(true);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        detector.onTouchEvent(event);
        return true;
    }


    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {
        Toast.makeText(this, "啊呀", Toast.LENGTH_SHORT).show();
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        if (velocityX < 0) {
            goNext();
        } else if (velocityX > 0) {
            goPrevious();
        }
        return true;
    }

    public void goNext() {
        index++;
        index = Math.abs(index % girls.length);
        image.setImageResource(girls[index]);
    }

    public void goPrevious() {
        index--;
        index = Math.abs(index % girls.length);
        image.setImageResource(girls[index]);
    }
}

使用OnGestureListener接口,这样需要重载OnGestureListener接口所有的方法,适合监听所有的手势,正如官方文档提到的“Detecing All Supported Gestures”,这样会造成有些手势动作我们用不到,但是还要重载。SimpleOnGestureListener类的出现为我们解决了这个问题。

public class MainActivity extends Activity {   
          
        private GestureDetectorCompat mDetector;   
      
        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_main);  
            mDetector = new GestureDetectorCompat(this, new MyGestureListener());  
     

onTouchEvent中使用了MotionEventCompat,而不直接使用MotionEvent是因为MotionEventCompat使更多的Action适配到API 4。
在View中使用手势:

View myView = findViewById(R.id.my_view);   
        myView.setOnTouchListener(new OnTouchListener() {  
            public boolean onTouch(View v, MotionEvent event) {  
                // ... Respond to touch events         
                this.mDetector.onTouchEvent(event);  
                return super.onTouchEvent(event);  
            }  
        });

手势添加:

Android中使用GestureLibrary来代表手势库,提供了GestureLibraries工具类来创建手势库。

四个加载手势库的静态方法:

这里写图片描述
获得GestureLibraries对象后,就可以使用该对象提供的下述方法来做相应操作了:

相关方法:

 

这里写图片描述

5.手势添加示例: 

public void addGesture (String entryName, Gesture gesture):添加一个名为entryName的手势   

public Set<String> getGestureEntries ():获得手势库中所有手势的名称  

public ArrayList<Gesture> getGestures (String entryName):获得entryName名称对应的全部手势 

public ArrayList<Prediction> recognize (Gesture gesture): 从当前手势库中识别与gesture匹配的全部手势
public void removeEntry (String entryName):删除手势库中entryName名称对应的手势 

public void removeGesture (String entryName, Gesture gesture):删除手势库中entryName和gesture都匹配的手势 

public abstract boolean save ():想手势库中添加手势或从中删除手势后调用该方法保存手势库 
GestureOverlayView手势编辑组件:
Android为GestureOverlayView提供了三种监听器接口,如下,一般常用的是:OnGesturePerformedListener;用于手势完成时提供响应!

运行效果图:
这里写图片描述

activity_main.xml:

<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:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请在下方屏幕中绘制手势~"
        android:textSize="20sp"/>


    <!-- gestureStrokeType控制手势是否需要一笔完成,multiple表示允许多笔-->
    <android.gesture.GestureOverlayView
        android:id="@+id/gesture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gestureStrokeType="multiple" />

</LinearLayout>
dialog_save.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="8dp"
            android:text="请填写手势名称:"/>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/edit_name"/>
    </LinearLayout>

    <ImageView
        android:id="@+id/img_show"
        android:layout_width="128dp"
        android:layout_height="128dp"
        android:layout_marginTop="10dp"/>

</LinearLayout>
public class MainActivity extends AppCompatActivity {

    private EditText editText;
    private GestureOverlayView gesture;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取手势编辑组件后,设置相关参数
        gesture = (GestureOverlayView) findViewById(R.id.gesture);
        gesture.setGestureColor(Color.GREEN);
        gesture.setGestureStrokeWidth(5);
        gesture.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
            @Override
            public void onGesturePerformed(GestureOverlayView gestureOverlayView, final Gesture gesture) {
                View saveDialog = getLayoutInflater().inflate(R.layout.dialog_save,null,false);
                ImageView img_show = (ImageView) saveDialog.findViewById(R.id.img_show);
                final EditText edit_name = (EditText) saveDialog.findViewById(R.id.edit_name);
                Bitmap bitmap = gesture.toBitmap(128,128,10,0xffff0000);
                img_show.setImageBitmap(bitmap);
                new AlertDialog.Builder(MainActivity.this).setView(saveDialog)
                        .setPositiveButton("保存",new DialogInterface.OnClickListener()
                        {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                //获取文件对应的手势库
                                GestureLibrary gestureLib = GestureLibraries.fromFile("/mnt/sdcard/mygestures");
                                gestureLib.addGesture(edit_name.getText().toString(),gesture);
                                gestureLib.save();
                            }
                        }).setNegativeButton("取消", null).show();
            }
        });
    }
}
识别手势:

public class MainActivity extends AppCompatActivity {

    private GestureOverlayView gesture;
    private GestureLibrary gestureLibrary;
    private Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        gestureLibrary = GestureLibraries.fromFile("mmt/sdcard/mygestures");
        if (gestureLibrary.load()) {
            Toast.makeText(mContext, "手势库加载成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(mContext, "手势库加载失败", Toast.LENGTH_SHORT).show();
        }

        //获取手势编辑组件后,设置相关参数
        gesture = (GestureOverlayView) findViewById(R.id.gesture);
        gesture.setGestureColor(Color.GREEN);
        gesture.setGestureStrokeWidth(5);
        gesture.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
            @Override
            public void onGesturePerformed(GestureOverlayView gestureOverlayView, final Gesture gesture) {
                //识别用户刚绘制的手势
                ArrayList<Prediction> predictions = gestureLibrary.recognize(gesture);
                ArrayList<String> result = new ArrayList<String>();
                //遍历所有找到的Prediction对象
                for (Prediction pred : predictions) {
                    if (pred.score > 2.0) {
                        result.add("与手势【" + pred.name + "】相似度为" + pred.score);
                    }
                }
                if (result.size() > 0) {
                    ArrayAdapter<Object> adapter = new ArrayAdapter<Object>(mContext,
                            android.R.layout.simple_dropdown_item_1line, result.toArray());
                    new AlertDialog.Builder(mContext).setAdapter(adapter,null).setPositiveButton("确定",null).show();
                }else{
                    Toast.makeText(mContext,"无法找到匹配的手势!",Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}
添加权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

参考:http://blog.csdn.net/xyz_lmn/article/details/16826669    

            http://www.jianshu.com/p/095e81f21e07

            http://blog.csdn.net/makeyourchance/article/details/51814749

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_29882585/article/details/74556042

智能推荐

2023年第七届强网杯初赛 WP_2023强网杯赛题-程序员宅基地

文章浏览阅读1.8k次,点赞22次,收藏21次。最坏情况下,前5次全输,需要87步即可达到260分,即第92轮时,因此可以通过本题。利用SQL注入修改data数据的值,本题data是数组,且会插入数据库,最终的payload需要改一下让前后闭合,且TP5,在网上找一个链子的EXP改一下。当然,前一题的SQL注入点依然存在,不过依然需要鉴权进入后台,这意味着,只需要我们能进入后台,就能通过load_file的方式读取flag。简单来说,就是能set任意的值,例如下方的payload,就能注入一个snowwolf的键,且值为wolf,4代表数据长度。_2023强网杯赛题

JavaWeb CURD 一键生成,再也不要重复搬砖了!【免费源码】_基于java类的curbecms-程序员宅基地

文章浏览阅读836次,点赞2次,收藏2次。简介本文将给您介绍 AppAdmin 后台管理系统开发框架。AppAdmin后台管理系统开发框架是一套Java开发的整合了当前众多比较流行的Java后台开发框架的系统,使用H5响应式布局。整合了 spring + springMVC + hibernate (JPA) + shiro + ehcache 等框架,功能包括基本的系统管理、权限、角色、存储(oss、本地、ftp)、缓存、站内信、..._基于java类的curbecms

记录:jackson报错问题:com.fasterxml.jackson.core.TSFBuilder-程序员宅基地

文章浏览阅读9.2k次。背景:java -jar启动报错,但是本地idea运行正常。环境:jdk1.8jackson: <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version&_com.fasterxml.jackson.core.tsfbuilder

Palworld幻兽帕鲁自建服务器教程,1分钟自建幻兽帕鲁服务器教程-程序员宅基地

文章浏览阅读77次。2024阿里云和腾讯云均推出专属幻兽帕鲁Palworld游戏优惠服务器,阿里云配置分为4核16G和4核32G服务器,4核16G配置32.25元/1个月、10M带宽66.30元/1个月、4核32G配置113.24元/1个月,4核32G配置3个月339.72元。幻兽帕鲁服务器官方推荐是4核16G配置,Windows和Linux服务器操作系统,Windows-Steam,Linux-SteamCMD,默认端口port=8211,玩家players=32。14带宽3个月277.2元,一年1584元。

网络由三十台计算机组成,自考网络教育计算机组成原理作业考试题及答案三套.doc...-程序员宅基地

文章浏览阅读85次。自考网络教育计算机组成原理作业考试题及答案三套计算机组成原理 一、单项选择题(本大题共100分,共 40 小题,每小题 2.5 分)1. CPU从主存取出一条指令并执行该指令的时间叫做( ) A. 机器周期 B. 指令周期 C. 时钟周期 D. 总线周期2. 同步控制是( ). A. 只适用于CPU控制的方式 B. 只适用于外围设备控制的方式 C. 由统一时序信号控制的方式 D. 所有指令控制时间..._30台计算机组成的网络

封印者与登录服务器的连接已中断,封印者闪退掉线黑屏怎么办 无法登陆如何解决...-程序员宅基地

文章浏览阅读1.1k次。封印者闪退掉线黑屏怎么办?游戏无法登陆如何解决?封印者是最近不删档的游戏,受到了不少玩家喜爱。有不少玩家反映在玩封印者出现了闪退等问题,那么如何解决上述问题呢?下面就和说玩网小编一起去看看吧。1、网络问题,有时候网络不好,链接不上游戏,就会出现闪退。解决方法:建议在玩家在WIFI环境下开始游戏,或者是3G/4G等网络环境较好的地方开始游戏。2、玩家手机内存不够,玩家手机的内存不够了,就会出现卡顿、..._封印者闪退解决方案

随便推点

指针的基本知识_指针指向的是值还是地址-程序员宅基地

文章浏览阅读1.4k次。指针一、指针是什么1、指针是什么?指针理解的2个要点:1. 指针是内存中一个最小单元的编号,也就是地址;2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量总结:指针就是地址,口语中说得指针通常值得是指针变量2、指针变量我们可以通过&(取地址操作符)取出变量的内存真实地址,吧地址可以存放到一个变量中,这个变量就是指针变量。实例#include <stdio.h> { int a=10; _指针指向的是值还是地址

力扣Leetcode 2 两数相加 Add Two Numbers_力扣 2. 两数相加 add two numbers 调试-程序员宅基地

文章浏览阅读85次。暴力法递归法_力扣 2. 两数相加 add two numbers 调试

单目深度估计评估指标_单目系统中的量化评估指标-程序员宅基地

文章浏览阅读7.6k次,点赞15次,收藏35次。KITTI Depth以及ScanNet评估指标 指标 名称 表达式 abs rel. absolute relative error mae mean absolute error log mae mean absolute logarithmic error imae inverse mean absolu..._单目系统中的量化评估指标

探索 `ansible-role-nginx`: 简化Nginx服务器配置的Ansible角色-程序员宅基地

文章浏览阅读870次,点赞7次,收藏20次。探索 ansible-role-nginx: 简化Nginx服务器配置的Ansible角色项目地址:https://gitcode.com/jdauphant/ansible-role-nginx在现代Web服务管理中,自动化运维工具起着至关重要的作用,而Ansible就是其中的一把利剑。今天我们要介绍的是一个由jdauphant维护的Ansible角色——ansible-role-nginx...

利用tkinter制作一个用户界面:开始研究界面的零件及细节_python tkinter 注册页面-程序员宅基地

文章浏览阅读555次,点赞2次,收藏4次。导入:我想作为一名Python程序猿,大家对于tkinter大家应该不陌生了吧,那么在接下几篇博文里我将跟大伙一起来实现tkinter的用户登录界面。注意:该界面没有注册哦~tkinter的基础:想要先实例化一个窗口我们就得学会以下代码:import tkinter as tkwindow = tk.Tk()window.title("xxx")window.geometry("300x500")#注意,引号中的窗口大小必须用"x",而不是“*”window.mainloop()运行了_python tkinter 注册页面

How Firewalls (Security Gateways) Handle the Packets? (Traffic Flow)-程序员宅基地

文章浏览阅读167次。Different firewall (security gateway) vendor has different solution to handle the passing traffic. This post compiles some useful Internet posts that interpret major vendors’ solutions including:1. C..._traffic@flow: nat: