欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新

Android Touch事件原理加实例分析,androidtouch

来源: 开发者 投稿于  被查看 42131 次 评论:40

Android Touch事件原理加实例分析,androidtouch


       Android中有各种各样的事件,以响应用户的操作。这些事件可以分为按键事件和触屏事件。而Touch事件是触屏事件的基础事件,在进行Android开发时经常会用到,所以非常有必要深入理解它的原理机制。

       Android Touch事件原理描述

       一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP。

       当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?我只能很肯定的对你说不一定。呵呵,为什么呢?看看下面我的调查结果你就明白了。

       Android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:

       1)public boolean dispatchTouchEvent(MotionEvent ev)  这个方法用来分发TouchEvent

       2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent

       3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent

       当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由  dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。

       Android Touch事件实例分析

       通过语言描述这个处理逻辑很抽象,下面我就用代码来具体说明一下。

       layout配置文件 main.xml:

XML/HTML代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <test.lzqdiy.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     android:gravity="center" >  
  7.        <test.lzqdiy.MyTextView    
  8.             android:layout_width="200px"  
  9.             android:layout_height="200px"  
  10.             android:id="@+id/tv"  
  11.             android:text="lzqdiy"  
  12.             android:textSize="40sp"  
  13.             android:textStyle="bold"  
  14.             android:background="#FFFFFF"  
  15.             android:textColor="#0000FF"/>  
  16. </test.lzqdiy.MyLinearLayout>  

       节点层次很简单,一个LinearLayout中添加了一个TextView。

       下面是java代码:

Java代码
  1. package test.lzqdiy;   
  2.   
  3. import android.app.Activity;   
  4. import android.os.Bundle;   
  5.   
  6. public class TestTouchEventApp extends Activity {   
  7.     /** Called when the activity is first created. */  
  8.     @Override  
  9.     public void onCreate(Bundle savedInstanceState) {   
  10.         super.onCreate(savedInstanceState);   
  11.         setContentView(R.layout.main);   
  12.     }   
  13. }   
  14. package test.lzqdiy;   
  15.   
  16. import android.content.Context;   
  17. import android.util.AttributeSet;   
  18. import android.util.Log;   
  19. import android.view.MotionEvent;   
  20. import android.widget.LinearLayout;   
  21.   
  22. public class MyLinearLayout extends LinearLayout {   
  23.     private final String TAG = "MyLinearLayout";   
  24.   
  25.     public MyLinearLayout(Context context, AttributeSet attrs) {     
  26.         super(context, attrs);     
  27.         Log.d(TAG, TAG);     
  28.     }   
  29.   
  30.     @Override  
  31.     public boolean dispatchTouchEvent(MotionEvent ev) {   
  32.         int action = ev.getAction();  
  33.    
  34.         switch (action) {     
  35.         case MotionEvent.ACTION_DOWN:     
  36.             Log.d(TAG, "dispatchTouchEvent action:ACTION_DOWN"); 
  37.             break;     
  38.         case MotionEvent.ACTION_MOVE:     
  39.             Log.d(TAG, "dispatchTouchEvent action:ACTION_MOVE"); 
  40.             break;     
  41.         case MotionEvent.ACTION_UP:     
  42.             Log.d(TAG, "dispatchTouchEvent action:ACTION_UP"); 
  43.             break;     
  44.         case MotionEvent.ACTION_CANCEL:     
  45.             Log.d(TAG, "dispatchTouchEvent action:ACTION_CANCEL"); 
  46.             break;     
  47.         }   
  48.  
  49.         return super.dispatchTouchEvent(ev);   
  50.     }   
  51.   
  52.     @Override  
  53.     public boolean onInterceptTouchEvent(MotionEvent ev) {     
  54.         int action = ev.getAction();  
  55.    
  56.         switch (action) {     
  57.         case MotionEvent.ACTION_DOWN:     
  58.             Log.d(TAG, "onInterceptTouchEvent action:ACTION_DOWN"); 
  59.             break;     
  60.         case MotionEvent.ACTION_MOVE:     
  61.             Log.d(TAG, "onInterceptTouchEvent action:ACTION_MOVE"); 
  62.             break;     
  63.         case MotionEvent.ACTION_UP:     
  64.             Log.d(TAG, "onInterceptTouchEvent action:ACTION_UP"); 
  65.             break;     
  66.         case MotionEvent.ACTION_CANCEL:     
  67.             Log.d(TAG, "onInterceptTouchEvent action:ACTION_CANCEL"); 
  68.             break;     
  69.         }     
  70.         return false;     
  71.     }   
  72.   
  73.     @Override  
  74.     public boolean onTouchEvent(MotionEvent ev) {     
  75.         int action = ev.getAction();   
  76.   
  77.         switch (action) {     
  78.         case MotionEvent.ACTION_DOWN:     
  79.             Log.d(TAG, "---onTouchEvent action:ACTION_DOWN");     
  80.             break;     
  81.         case MotionEvent.ACTION_MOVE:     
  82.             Log.d(TAG, "---onTouchEvent action:ACTION_MOVE");     
  83.             break;     
  84.         case MotionEvent.ACTION_UP:     
  85.             Log.d(TAG, "---onTouchEvent action:ACTION_UP");     
  86.             break;     
  87.         case MotionEvent.ACTION_CANCEL:     
  88.             Log.d(TAG, "---onTouchEvent action:ACTION_CANCEL");   
  89.             break;     
  90.         }   
  91.   
  92.         return true;   
  93.     }   
  94.   
  95. }   
  96.   
  97. package test.lzqdiy;   
  98.   
  99. import android.content.Context;   
  100. import android.util.AttributeSet;   
  101. import android.util.Log;   
  102. import android.view.MotionEvent;   
  103. import android.widget.TextView;   
  104.   
  105. public class MyTextView extends TextView {   
  106.   
  107.     private final String TAG = "MyTextView";   
  108.   
  109.     public MyTextView(Context context, AttributeSet attrs) {     
  110.         super(context, attrs);     
  111.     }   
  112.   
  113.     @Override  
  114.     public boolean dispatchTouchEvent(MotionEvent ev) {   
  115.         int action = ev.getAction();   
  116.   
  117.         switch (action) {     
  118.         case MotionEvent.ACTION_DOWN:     
  119.             Log.d(TAG, "dispatchTouchEvent action:ACTION_DOWN"); 
  120.             break;     
  121.         case MotionEvent.ACTION_MOVE:     
  122.             Log.d(TAG, "dispatchTouchEvent action:ACTION_MOVE"); 
  123.             break;     
  124.         case MotionEvent.ACTION_UP:     
  125.             Log.d(TAG, "dispatchTouchEvent action:ACTION_UP");     
  126.             break;     
  127.         case MotionEvent.ACTION_CANCEL:     
  128.             Log.d(TAG, "onTouchEvent action:ACTION_CANCEL");     
  129.             break;     
  130.         } 
  131.   
  132.         return super.dispatchTouchEvent(ev);   
  133.     }   
  134.   
  135.     @Override  
  136.     public boolean onTouchEvent(MotionEvent ev) {     
  137.         int action = ev.getAction();   
  138.   
  139.         switch (action) {     
  140.         case MotionEvent.ACTION_DOWN:     
  141.             Log.d(TAG, "---onTouchEvent action:ACTION_DOWN");     
  142.             break;     
  143.         case MotionEvent.ACTION_MOVE:     
  144.             Log.d(TAG, "---onTouchEvent action:ACTION_MOVE");     
  145.             break;     
  146.         case MotionEvent.ACTION_UP:     
  147.             Log.d(TAG, "---onTouchEvent action:ACTION_UP");     
  148.             break;     
  149.         case MotionEvent.ACTION_CANCEL:     
  150.             Log.d(TAG, "---onTouchEvent action:ACTION_CANCEL");     
  151.             break;     
  152.         }   
  153.   
  154.         return true;     
  155.     }     
  156. }  

       为了指代方便,下面将MyLinearLayout简称为L,将MyTextView简称为T,L.onInterceptTouchEvent=true 表示的含义为MyLinearLayout中的onInterceptTouchEvent方法返回值为true,通过程序运行时输出的Log来说明调用时序。

       第1种情况 L.onInterceptTouchEvent=false&& L.onTouchEvent=true &&T.onTouchEvent=true 输出下面的Log:

D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_DOWN
D/MyTextView(11865): dispatchTouchEvent action:ACTION_DOWN
D/MyTextView(11865): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_MOVE
D/MyTextView(11865): dispatchTouchEvent action:ACTION_MOVE
D/MyTextView(11865): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_UP
D/MyTextView(11865): dispatchTouchEvent action:ACTION_UP
D/MyTextView(11865): ---onTouchEvent action:ACTION_UP

       结论:TouchEvent完全由TextView处理。

       第2种情况  L.onInterceptTouchEvent=false&& L.onTouchEvent=true &&T.onTouchEvent=false 输出下面的Log:

D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): onInterceptTouchEvent action:ACTION_DOWN
D/MyTextView(13101): dispatchTouchEvent action:ACTION_DOWN
D/MyTextView(13101): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_UP

       结论:TextView只处理了ACTION_DOWN事件,LinearLayout处理了所有的TouchEvent。

       第3种情况  L.onInterceptTouchEvent=true&& L.onTouchEvent=true 输出下面的Log:

D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): onInterceptTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_UP

       结论:LinearLayout处理了所有的TouchEvent。

       第4种情况  L.onInterceptTouchEvent=true&& L.onTouchEvent=false 输出下面的Log:

D/MyLinearLayout(13452): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13452): onInterceptTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13452): ---onTouchEvent action:ACTION_DOWN

       结论:LinearLayout只处理了ACTION_DOWN事件,那么其他的TouchEvent被谁处理了呢?答案是LinearLayout最外层的Activity处理了TouchEvent。


android onclick事件与ontouch事件是否会冲突

Button的onTouch,onClick,onLongClick事件发生先后顺序和关联:
一,onTouch返回false
首先是onTouch事件的down事件发生,此时,如果长按,触发onLongClick事件;
然后是onTouch事件的up事件发生,up完毕,最后触发onClick事件。

二,onTouch返回true
首先是onTouch事件的down事件发生,然后是onTouch事件的up事件发生;期间不触发onClick和onLongClick事件

三,onTouch:down返回true,up返回false:结果同二。
机制分析:
onTouch事件中:down事件返回值标记此次事件是否为点击事件(返回false,是点击事件;返回true,不记为点击事件),而up事件标记此次事件结束时间,也就是判断是否为长按。
只要当down返回true时候,系统将不把本次事件记录为点击事件,也就不会触发onClick或者onLongClick事件了。因此尽管当up的时候返回false,系统也不会继续触发onClick事件了。

四,onTouch:down返回false,up返回true:
首先是onTouch事件的down事件发生,此时:
长按,触发onLongClick事件,然后是onTouch事件的up事件发生,完毕。
短按,先触发onTouch的up事件, 到一定时间后,自动触发onLongClick事件。
机制分析:
onTouch事件中:down事件返回值标记此次事件是否为点击事件(返回false,是点击事件;返回true,不记为点击事件),而up事件标记此次事件结束时间,也就是判断是否为长按。
当down返回false,标记此次事件为点击事件,而up返回了true,则表示此次事件一直没有结束,也就是一直长按下去了,达到长按临界时间后,自然触发长按事件,而onClick事件没有触发到
 

android的ontouch事件的示例

View.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {

if(event.getAction()==MotionEvent.ACTION_DOWN){

}else if(event.getAction()==MotionEvent.ACTION_MOVE){

}else if(event.getAction()==MotionEvent.ACTION_UP){

}
return false;
}
});
 

用户评论