面试的时候曾被问过这两个方法的调用顺序,当时也只是知道onInterceptTouchEvent在前,具体的执行过程,相互的影响却不知道.今天写了一个小demo详细研究了一下这两个方法之间的关系.
首先上代码:
主activity:InterceptTouchStudyActivity
package com.touchstudy; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class InterceptTouchStudyActivity extends Activity { TextView tv; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
布局文件main.xml
<?xml version="1.0" encoding="utf-8"?> <com.touchstudy.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <com.touchstudy.LayoutView2 android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:orientation="vertical" > <com.touchstudy.MyTextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#FFFFFF" android:text="AB" android:textColor="#0000FF" android:textSize="40sp" android:textStyle="bold" /> </com.touchstudy.LayoutView2> </com.touchstudy.LayoutView1>
类LayoutView1
package com.touchstudy; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.LinearLayout; public class LayoutView1 extends LinearLayout { private final String TAG = "LayoutView1"; public LayoutView1(Context context, AttributeSet attrs) { super(context, attrs); Log.d(TAG, TAG); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.d(TAG, "onInterceptTouchEvent1 action:ACTION_DOWN"); // return true; break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onInterceptTouchEvent1 action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG, "onInterceptTouchEvent1 action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG, "onInterceptTouchEvent1 action:ACTION_CANCEL"); break; } boolean b = false; Log.d(TAG, "onInterceptTouchEvent1 return:"+b); return b; } @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.d(TAG, "onTouchEvent1 action:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onTouchEvent1 action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG, "onTouchEvent1 action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG, "onTouchEvent1 action:ACTION_CANCEL"); break; } boolean b = false; Log.d(TAG, "onTouchEvent1 return:"+b); return b; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub super.onLayout(changed, l, t, r, b); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
类LayoutView2
package com.touchstudy; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.LinearLayout; public class LayoutView2 extends LinearLayout { private final String TAG = "LayoutView2"; public LayoutView2(Context context, AttributeSet attrs) { super(context, attrs); Log.d(TAG, TAG); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.d(TAG, "onInterceptTouchEvent2 action:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onInterceptTouchEvent2 action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG, "onInterceptTouchEvent2 action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG, "onInterceptTouchEvent2 action:ACTION_CANCEL"); break; } boolean b = false; Log.d(TAG, "onInterceptTouchEvent2 return:"+b); return b; } @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.d(TAG, "onTouchEvent2 action:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onTouchEvent2 action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG, "onTouchEvent2 action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG, "onTouchEvent2 action:ACTION_CANCEL"); break; } boolean b = false; Log.d(TAG, "onTouchEvent2 return:"+b); return b; } }
类MyTextView
package com.touchstudy; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; public class MyTextView extends TextView { private final String TAG = "MyTextView"; public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); Log.d(TAG, TAG); } @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.d(TAG, "onTouchEvent_TextView action:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onTouchEvent_TextView action:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG, "onTouchEvent_TextView action:ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG, "onTouchEvent_TextView action:ACTION_CANCEL"); break; } boolean b = false; Log.d(TAG, "onTouchEvent_TextView return:"+b); return b; } public void onClick(View v) { Log.d(TAG, "onClick"); } public boolean onLongClick(View v) { Log.d(TAG, "onLongClick"); return false; } }
onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,由于ViewGroup会包含若干childView,因此需要能够统一监控各种touch事件的机会,因此纯粹的不能包含子view的控件是没有这个方法的,如LinearLayout就有,TextView就没有。
关于返回值的问题,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理,需要说明的是,如果 onTouchEvent针对down事件返回了false,那么之后的move和up事件即使没有被拦截,也是接收不到的,或者说识别不了.
onInterceptTouchEvent()使用也很简单,如果在ViewGroup里覆写了该方法,那么就可以对各种touch事件加以拦截。但是如何拦截,是否所有的touch事件都需要拦截则是比较复杂的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各个childView间的传递机制完全取决于onInterceptTouchEvent()和onTouchEvent()的返回值。并且,针对down事件处理的返回值直接影响到后续move和up事件的接收和传递。
总结一下,基本的规则是:
1. 对于一个事件,如果没有被任何view拦截的话(所有方法都返回false),全程的顺序是
LayoutView1->LayoutView2->MyTextView依次调用onInterceptTouchEvent()
然后MyTextView->LayoutView2->LayoutView1依次调用onTouchEvent()
2. onInterceptTouchEvent()只负责拦截不拦截,onTouchEvent()只负责处理不处理,两者只要返回true,该事件就停止向后传递.
3. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理.
4. 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。
5. 如果最终需要处理事件的view 的onTouchEvent()返回了true,则上一层次的view收不到该事件,且后续事件将可以继续传递给该view的onTouchEvent()处理.
下面开始在代码中试验.
1.onInterceptTouchEvent()处理事件均返回false,onTouchEvent()处理事件均返回true
这是最常见的情况,onInterceptTouchEvent并没有做任何改变事件传递时序的操作,效果上和没有覆写该方法是一样的。可以看到,各种事件的传递本身是自底向上的,次序是:LayoutView1->LayoutView2->MyTextView。事件在MyTextView的OnTouch中被处理,停止了向父组件传递.
2.LayoutView1的onInterceptTouchEvent()处理事件返回true,MyTextView的onTouchEvent()处理事件返回true
由于LayoutView1在拦截第一次事件时return true,所以后续的事件(包括第一次的down)将由LayoutView1本身处理,事件不再传递下去。
3.LayoutView1,LayoutView2的onInterceptTouchEvent()处理事件返回false,MyTextView的onTouchEvent()处理事件返回false,LayoutView2的onTouchEvent()处理事件返回true
由于MyTextView在onTouchEvent()中return false,down事件被传递给其父view,即LayoutView2的onTouchEvent()方法处理,由于在LayoutView2的onTouchEvent()中return true,所以down事件传递并没有上传到LayoutView1。注意,后续的move和up事件均被传递给LayoutView2的onTouchEvent()处理,而没有传递给MyTextView。
发表评论
-
android应用程序中获取view的位置
2012-08-16 14:35 26245我们重点在获取view的y坐标,你懂的... 依次介绍以下四 ... -
获取设备sdk版本,生产商等参数(待续)
2012-04-27 14:40 1185获得设备版本,比如是平板或者手机 android.os.Bu ... -
android中画虚线--.PathEffect类简单认识
2012-04-16 14:59 37054Paint p = new Paint(Paint.ANTI_ ... -
android截取屏幕图片
2012-04-12 09:16 3318代码如下: package com.iceman.pr ... -
自定义view中获取字符串的宽度和高度
2012-03-28 16:44 1738方法1: Rect rect = new Rect(); ... -
width和height对weight的影响
2012-03-26 17:25 1422weight是比重,在线性布局中用来分配各组件的空间. 由于方 ... -
android画各种几何图形
2012-03-23 14:49 8170继承自Android.view.View的 MyView类,重 ... -
android语音识别简单实现
2012-03-20 17:22 1711首先,你的设备要支持语音识别,这属于android的一个框架, ... -
去除gridview中点击时出现的黄色边框
2012-03-20 16:51 2621最近做一个小键盘,每个按钮都已经设置了按下时的背景图片.但是在 ...
相关推荐
在博客《onTouchEvent 、onInterceptTouchEvent的顺序》中,作者可能详细解释了这两个方法在实际应用中的操作流程: 1. **默认行为**: 当用户触摸屏幕时,事件首先由父视图的 `dispatchTouchEvent` 处理,如果父...
在Android开发中,触摸事件的处理是用户交互的基础,而`onTouchEvent`和`onInterceptTouchEvent`则是处理这些事件的关键方法。这篇文章将深入解析这两个方法的区别和它们在触摸事件处理链中的作用。 首先,`...
通过查看博客链接(已提供但无法直接访问)和研究`InterceptTouchStudyActivity`的源代码,开发者可以更深入地理解这些概念,并学会如何在实践中应用。源码分析可以帮助我们看到事件分发的实际运行情况,从而加深对...
`onInterceptTouchEvent`和`onTouchEvent`是两个至关重要的方法,它们共同构成了Android视图层次结构中的触摸事件分发机制。下面我们将深入探讨这两个方法的用法及其在实际开发中的应用场景。 1. `...
`onInterceptTouchEvent`和`onTouchEvent`是两个关键的方法,它们共同构成了Android事件分发机制的核心。 `onInterceptTouchEvent`方法在ViewGroup中定义,它的主要作用是拦截事件流,即决定事件是否由父视图处理,...
`onInterceptTouchEvent`和`onTouchEvent`是两个关键的方法,它们协同工作以处理触摸屏幕的动作。这篇文章将深入探讨这两个方法的调用关系及其在Android事件分发机制中的作用。 首先,我们要理解Android的事件分发...
`onInterceptTouchEvent`和`onTouchEvent`是两个核心的方法,它们共同决定了Android应用如何响应用户的触摸操作。这两个方法主要在ViewGroup(如布局)和View(如按钮、文本框等)中被使用。 首先,我们来理解`...
当`onInterceptTouchEvent`返回true时,表示ViewGroup想要拦截并处理事件,之后的事件序列将不再分发给子View,而是直接交给`onTouchEvent`。如果返回false,事件将继续传递给子View。 在实际应用中,`...
Android事件分发机制可以分为三个主要步骤:dispatchTouchEvent、onTouchEvent和onInterceptTouchEvent。当用户在屏幕上进行触控操作时,这些方法会依次被调用来决定事件如何被处理。 1. **dispatchTouchEvent**: ...
事件传递方法包括dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent,其中前两个是View和ViewGroup都有的,最后一个是只有ViewGroup才有的方法。这三个方法的作用分别是负责事件分发、事件处理、事件拦截。 ...
在Android开发中,触摸事件处理是用户界面交互的关键部分,`onInterceptTouchEvent`和`onTouchEvent`是处理这些事件的两个重要方法。本篇文章将深入探讨`onInterceptTouchEvent`,并结合`onTouchEvent`讲解它们的...
本篇将详细讲解如何通过重写`onTouchEvent`来实现上下左右滑动事件。 首先,我们需要了解Android中的MotionEvent类,它是所有触摸事件的容器,包含了触摸事件的各种信息,如ACTION_DOWN(手指按下)、ACTION_UP...
`onInterceptTouchEvent(MotionEvent ev)` 和 `dispatchTouchEvent(MotionEvent ev)` 是View和ViewGroup在处理触摸事件时的两个关键方法,它们共同构成了触摸事件的分发机制。了解这两个方法的工作原理对于优化用户...
下面将详细解析这两个方法的工作原理和应用场景。 首先,`onInterceptTouchEvent(MotionEvent ev)` 是ViewGroup特有的方法,用于拦截子视图的触摸事件。当用户触摸屏幕时,Android会生成一个MotionEvent序列,这个...
首先,我们需要自定义一个继承ViewPager的类,重写onTouchEvent和onInterceptTouchEvent方法,使用swapTouchEvent方法将MotionEvent事件的x坐标换成y坐标,而y坐标换成x坐标。这个方法是将横向滑动转换成纵向滑动的...
在描述中提到的博客链接(由于无法直接访问,以下内容基于一般知识推测)很可能详细解释了如何重写`onInterceptTouchEvent`和`onTouchEvent`来实现自定义的事件分发逻辑。这可能包括了如何在仿ViewPager中判断滑动...
通常,这样的测试会包含创建自定义View或ViewGroup,重写`onInterceptTouchEvent`和`onTouchEvent`,并设置各种触摸事件场景以验证事件分发和拦截的逻辑是否正确。测试中可能涉及的动作包括按下、移动和释放,以及...
- **OnTouchEvent和onInterceptTouchEvent**:在滑动界面中,ViewGroup(如LinearLayout、RelativeLayout)需要决定是否拦截触摸事件。onInterceptTouchEvent方法用于父视图截取触摸事件,onTouchEvent则用于处理子...
- 事件拦截与派发方案,通过重写onInterceptTouchEvent和onTouchEvent来处理滑动事件。 - 基于NestingScrolling机制,利用NestedScrollView和NestedScrollingChild接口。 - 基于CoordinatorLayout和Behavior,...