您的位置:首页 > 移动开发 > Android开发

android中的划屏事件 GestureDetector.OnGestureListener 详解(二)

2014-07-15 10:52 429 查看
按下(onDown): 刚刚手指接触到触摸屏的那一刹那,就是触的那一下。

抛掷(onFling): 手指在触摸屏上迅速移动,并松开的动作。

长按(onLongPress): 手指按在持续一段时间,并且没有松开。

滚动(onScroll): 手指在触摸屏上滑动。

按住(onShowPress): 手指按在触摸屏上,它的时间范围在按下起效,在长按之前。

抬起(onSingleTapUp):手指离开触摸屏的那一刹那。

除了这些定义之外,鄙人也总结了一点算是经验的经验吧,在这里和大家分享一下。

任何手势动作都会先执行一次按下(onDown)动作。

长按(onLongPress)动作前一定会执行一次按住(onShowPress)动作。

按住(onShowPress)动作和按下(onDown)动作之后都会执行一次抬起(onSingleTapUp)动作。

长按(onLongPress)、滚动(onScroll)和抛掷(onFling)动作之后都不会执行抬起(onSingleTapUp)动作。

当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等,我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)Android
sdk给我们提供了GestureDetector(Gesture:手势Detector:识别)类,通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势,但是不同的手势要怎么处理,应该是提供给程序员实现的,因此这个类对外提供了两个接口:OnGestureListener,OnDoubleTapListener,还有一个内部类SimpleOnGestureListener,SimpleOnGestureListener类是GestureDetector提供给我们的一个更方便的响应不同手势的类,这个类实现了上述两个接口(但是所有的方法体都是空的),该类是static
class,也就是说它实际上是一个外部类。程序员可以在外部继承这个类,重写里面的手势处理方法。

通过GestureDetector的构造方法可以将SimpleOnGestureListener对象传递进去,这样GestureDetector能处理不同的手势了。

有时候我们并不需要处理上面所有手势,方便起见,Android提供了另外一个类SimpleOnGestureListener实现了如上接口,我们只需要继承SimpleOnGestureListener然后重载感兴趣的手势即可。

对于自定义View,使用手势识别有两处陷阱可能会浪费你的不少时间。

 

1:View必须设置longClickable为true,否则手势识别无法正确工作,只会返回Down, Show, Long三种手势

 

2:必须在View的onTouchListener中调用手势识别,而不能像Activity一样重载onTouchEvent,否则同样手势识别无法正确工作

定义GestureDetector时

会提示



构造器已经弃用

要加上忽视警告

语句:@SuppressWarnings("deprecation")  



GestureDetector会被划上

条横线

代表此语句已经过时

修改:

<span style="font-size: 18px;">随着<a target=_blank target="_blank" class="inner-link decor-none" href="http://zhidao.baidu.com/search?word=Android%20SDK&fr=qb_search_exp&ie=utf8" rel="nofollow" style="color: rgb(45, 100, 179); text-decoration: none;">Android SDK</a><img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />升级<img src="http://img.iknow.bdimg.com/question/word/comma.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/yi3.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />前<img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />某些接口<img src="http://img.iknow.bdimg.com/question/word/ke.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />能有更好、更安全<img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />接口来代替<img src="http://img.iknow.bdimg.com/question/word/stop.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />Android开发团队会把过时<img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />接口标识成deprecated, <img src="http://img.iknow.bdimg.com/question/word/ran.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/hou.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/zai.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />开发文档<img src="http://img.iknow.bdimg.com/question/word/zhong.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />提示使用<img src="http://img.iknow.bdimg.com/question/word/zui.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />新<img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />代替接口<img src="http://img.iknow.bdimg.com/question/word/stop.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />
<img src="http://img.iknow.bdimg.com/question/word/ni.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />用<img src="http://img.iknow.bdimg.com/question/word/dao.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />GestureDetector<img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><a target=_blank target="_blank" class="inner-link decor-none" href="http://zhidao.baidu.com/search?word=%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0&fr=qb_search_exp&ie=utf8" rel="nofollow" style="color: rgb(45, 100, 179); text-decoration: none;">构造函数</a><img src="http://img.iknow.bdimg.com/question/word/zai.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />4.1版本<img src="http://img.iknow.bdimg.com/question/word/zhong.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />已经过时<img src="http://img.iknow.bdimg.com/question/word/comma.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/ke.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/yi3.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />使用推荐<img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />:
mGestureDetector = new GestureDetector(this, this);
// 注意前<img src="http://img.iknow.bdimg.com/question/word/yi1.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/ge.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />this代表<img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/shi.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/yi1.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/ge.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />Context,<img src="http://img.iknow.bdimg.com/question/word/hou.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/yi1.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/ge.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />this代表<img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/shi.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/yi1.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/ge.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />OnGestureListener<img src="http://img.iknow.bdimg.com/question/word/stop.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />
// Activity继承自Context, 而<img src="http://img.iknow.bdimg.com/question/word/ni.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /><img src="http://img.iknow.bdimg.com/question/word/de.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" />activity应该实现了(implements)OnGestureListener接口<img src="http://img.iknow.bdimg.com/question/word/stop.png" class="word-replace" alt="" style="border: 0px; max-width: 100%; vertical-align: middle;" /></span>


2.、具体用法:Android Touch Screen 与传统Click Touch Screen不同,会有一些手势(Gesture),例如Fling,Scroll等等。这些Gesture会使用户体验大大提升。Android中的Gesture识别(detector)是通过GestureDetector.OnGestureListener接口实现的。

首先,Android事件处理机制是基于Listener实现的,比如触摸屏相关的事件,就是通过onTouchListener实现;

其次,所有View的子类都可以通过setOnTouchListener()、setOnKeyListener()等方法来添加对某一类事件的Listener;

第三,Listener一般会以Interface的方式来提供,其中包含一个或多个abstract方法,我们需要实现这些方法来完成onTouch()、onKey()等操作。这样,程序便可以在特定的事件被dispatch到该view的时候,通过callback函数给予适当的响应。

1. Touch Screen Click举例

Java代码 

 





public class MyGesture extends Activity implements OnTouchListener {
  

    public void onCreate(Bundle savedInstanceState) {
  

        super.onCreate(savedInstanceState);
  

        setContentView(R.layout.main);   

        TextView tv = (TextView) findViewById(R.id.tv);   

        tv.setOnTouchListener(this);
  

    }   

    public boolean onTouch(View v, MotionEvent event) {
  

        Toast.makeText(this, "Touch Touch", Toast.LENGTH_SHORT).show();
  

        return false;
  

    }   

}  

我们可以通过MotionEvent的getAction()方法来获取Touch事件的类型,包括 ACTION_DOWN(按下触摸屏), ACTION_MOVE(按下触摸屏后移动受力点), ACTION_UP(松开触摸屏)和ACTION_CANCEL(不会由用户直接触发)。借助对于用户不同操作的判断,结合getRawX()、getRawY()、getX()和getY()等方法来获取坐标后,我们可以实现诸如拖动某一个按钮,拖动滚动条等功能。

2. 回到今天的重点,当我们捕捉到Touch操作的时候,如何识别出用户的Gesture?这里我们需要GestureDetector.OnGestureListener接口的帮助,代码如下:

Java代码 

 





public class MyGesture extends Activity implements OnTouchListener, OnGestureListener {
  

    private GestureDetector mGestureDetector;
  

    public MyGesture() {
  

        mGestureDetector = new GestureDetector(this);
  

    }   

    public void onCreate(Bundle savedInstanceState) {
  

        super.onCreate(savedInstanceState);
  

        setContentView(R.layout.main);   

        TextView tv = (TextView) findViewById(R.id.tv);   

        tv.setOnTouchListener(this);
  

        tv.setFocusable(true);
  

        tv.setClickable(true);
  

        tv.setLongClickable(true);
  

        mGestureDetector.setIsLongpressEnabled(true);
  

    }   

       

    /*  

     * 在onTouch()方法中,我们调用GestureDetector的onTouchEvent()方法,将捕捉到的MotionEvent交给GestureDetector  

     * 来分析是否有合适的callback函数来处理用户的手势  

     */ 
  

    public boolean onTouch(View v, MotionEvent event) {
  

        return mGestureDetector.onTouchEvent(event);
  

    }   

  

    // 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发   

    public boolean onDown(MotionEvent arg0) {
  

        Log.i("MyGesture", "onDown");
  

        Toast.makeText(this, "onDown", Toast.LENGTH_SHORT).show();
  

        return true;
  

    }   

       

    /*  

     * 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发  

     * 注意和onDown()的区别,强调的是没有松开或者拖动的状态  

     */  

    public void onShowPress(MotionEvent e) {
  

        Log.i("MyGesture", "onShowPress");
  

        Toast.makeText(this, "onShowPress", Toast.LENGTH_SHORT).show();
  

    }   

       

    // 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发   

    public boolean onSingleTapUp(MotionEvent e) {
  

        Log.i("MyGesture", "onSingleTapUp");
  

        Toast.makeText(this, "onSingleTapUp", Toast.LENGTH_SHORT).show();
  

        return true;
  

    }   

       

    // 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发   

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  

        Log.i("MyGesture", "onFling");
  

        Toast.makeText(this, "onFling", Toast.LENGTH_LONG).show();
  

        return true;
  

    }   

       

    // 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发   

    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
  

        Log.i("MyGesture", "onScroll");
  

        Toast.makeText(this, "onScroll", Toast.LENGTH_LONG).show();
  

        return true;
  

    }   

       

    // 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发   

    public void onLongPress(MotionEvent e) {
  

        Log.i("MyGesture", "onLongPress");
  

        Toast.makeText(this, "onLongPress", Toast.LENGTH_LONG).show();
  

    }   

}  

滑屏实现:

 

通过android.view.GestureDetector类可以检测各种手势事件,该类有两个回调接口分别用来通知具体的事件:

 

GestureDetector.OnDoubleTapListener:用来通知DoubleTap事件,类似于鼠标的双击事件,该接口有如下三个回调函数:

 

1.   onDoubleTap(MotionEvent e):通知DoubleTap手势,

2.   onDoubleTapEvent(MotionEvent e):通知DoubleTap手势中的事件,包含down、up和move事件(这里指的是在双击之间发生的事件,例如在同一个地方双击会产生DoubleTap手势,而在DoubleTap手势里面还会发生down和up事件,这两个事件由该函数通知);

3.   onSingleTapConfirmed(MotionEvent e):用来判定该次点击是SingleTap而不是DoubleTap,如果连续点击两次就是DoubleTap手势,如果只点击一次,系统等待一段时间后没有收到第二次点击则判定该次点击为SingleTap而不是DoubleTap,然后触发SingleTapConfirmed事件。

GestureDetector.OnGestureListener:用来通知普通的手势事件,该接口有如下六个回调函数:

1.   onDown(MotionEvent e):down事件;

2.   onSingleTapUp(MotionEvent e):一次点击up事件;

3.   onShowPress(MotionEvent e):down事件发生而move或则up还没发生前触发该事件;

4.   onLongPress(MotionEvent e):长按事件;

5.   onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY):滑动手势事件;

6.   onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY):在屏幕上拖动事件。

本次仅用到了OnGestureListener类中的onFling方法。  其他手势事件各位可以自己回去试验。

简单说明:

要实现屏幕切换的话,首先需要定义一个GestureDetector:
private GestureDetector mGestureDetector;
 
并在onCreate函数中初始化:
mGestureDetector = new GestureDetector(this);
 
同时Activity要继承OnGestureListener接口,并实现其中的onFling方法。
另外Activity的onTouchEvent事件也要实现!!

另外本例View切换时还有动画效果。使用Animation类实现,相关的函数: 
setInAnimation:设置View进入屏幕时候使用的动画,该函数有两个版本:
一个接受单个参数,类型为android.view.animation.Animation;
一个接受两个参数,类型为Context和int,分别为Context对象和定义Animation的resourceID。
setOutAnimation: 设置View退出屏幕时候使用的动画,参数setInAnimation函数一样。
showNext: 调用该函数来显示FrameLayout里面的下一个View。
showPrevious: 调用该函数来显示FrameLayout里面的上一个View。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: