2 u010598929 u010598929 于 2016.04.01 00:05 提问

为什么onTouchEvent方法会在dispatchTouchEvent方法之前执行呢?

新建一个类MyButton,该类继承自Button
然后重写其中的onTouchEvent和dispatchTouchEvent方法

 public class MyButton extends Button {

    private Context mContext;

    public MyButton(Context context) {
        super(context);
        this.mContext = context;
    }

    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:DOWN");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:MOVE");
            break;
        case MotionEvent.ACTION_UP:
            Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:UP");
            break;
        }
        Log.d("TTTT", "========================== ");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d("TTTT", "context:" + mContext + "MyButton|onTouchEvent|return:" + super.onTouchEvent(event) + "|event:DOWN");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("TTTT", "context:" + mContext + "MyButton|onTouchEvent|return:" + super.onTouchEvent(event) + "|event:MOVE");
            break;
        case MotionEvent.ACTION_UP:
            Log.d("TTTT", "context:" + mContext + "MyButton|onTouchEvent|return:" + super.onTouchEvent(event) + "|event:UP");
            break;
        }
        return super.onTouchEvent(event);
    }
}

然后将这个Button加入到布局文件中,然后在Activity中给这个Button设置一个onTouchListener

 <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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.testtouchevent.MainActivity" >

    <com.example.testtouchevent.MyButton
        android:id="@+id/bt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮" />

</LinearLayout>

 public class MainActivity extends Activity {

    private Button bt;

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

        bt = (Button) findViewById(R.id.bt);

        bt.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
    }
}

按下按钮时候,log显式

 03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:DOWN
03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|dispatchTouchEvent|return:true|event:DOWN
03-31 11:51:08.493: D/TTTT(1609): ========================== 
03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:DOWN

松开按钮时候,log显式:

 03-31 11:51:10.285: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:UP
03-31 11:51:10.285: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|dispatchTouchEvent|return:true|event:UP
03-31 11:51:10.285: D/TTTT(1609): ========================== 
03-31 11:51:10.289: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:UP

可见onTouchEvent方法是在dispatchTouchEvent方法之前执行的
可是View的事件传递机制不是dispatchTouchEvent方法先执行用来传递消息的吗?
请问这是怎么回事儿?

3个回答

CSDNXIAON
CSDNXIAON   2016.04.01 00:12
已采纳

View 中的dispatchTouchEvent,OnInterceptTouchEvent ,OnTouchEvent方法
Activity调用dispatchTouchEvent()和onTouchEvent()方法
onTouch、onkey、dispatchTouchEvent、dispatchKeyEvent等方法被执行 “两次” 的解决方法
----------------------同志你好,我是CSDN问答机器人小N,奉组织之命为你提供参考答案,编程尚未成功,同志仍需努力!

szw_sh
szw_sh   2016.04.01 13:34

应该是button是最后一层,没有子类了,事件传递是向子类传递,如果没有子类就会调用onTouchEvent方法

u010598929
u010598929 向子类传递应该是针对ViewGroup来说的吧,这里并不存在ViewGroup,只是单传的View中事件传递,不过已经找到问题所在了,因为我在MyButton的Log里面先执行了super.dispatchTouchEvent(event),所以才会出现那个情况,还是多谢你了
2 年多之前 回复
u012215068
u012215068   2016.04.01 15:25

首先,button的enabled默认为true,那么在没有OnTouchListener或者有OnTouchListener但是返回false的时候,会第一时间传递给onTouchEvent,
第二,当前Button是最后一级,没有子类可派发事件

u010598929
u010598929 向子类传递应该是针对ViewGroup来说的吧,这里并不存在ViewGroup,只是单传的View中事件传递,不过已经找到问题所在了,因为我在MyButton的Log里面先执行了super.dispatchTouchEvent(event),所以才会出现那个情况,还是多谢你了
2 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐
Fragment中通过回调获得实现Activity中的onTouchEvent函数
该方法分为两步,首先是在父类Activity中,构造一个回调接口,并向外提供注册和销毁该回调接口的方法。然后在Activity的dispatchTouchEvent函数中遍历所有注册了该回调接口的对象,分发onTouchEvent事件。   /** * 回调接口 * @author zhaoxin5 * */ public interface MyTouchListener {
Activity调用dispatchTouchEvent()和onTouchEvent()方法
public class MyTextView extends TextView { public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyTextView(Context context, At
android Fragment中没有onTouchEvent解决方法
public interface MyTouchListener { public void onTouchEvent(MotionEvent event); } // 保存MyTouchListener接口的列表 private ArrayList myTouchListeners = new ArrayList(); /** * 提供给Fragment通过getAc
Android进阶——Android事件分发机制之dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
前言 Android事件分发机制可以说是我们Android工程师面试题中的必考题,弄懂它的原理是我们避不开的任务,所以长痛不如短痛,花点时间干掉他,废话不多说,开车啦 Android事件分发机制的简介 Android事件分发机制的发生在View与View之间或者ViewGroup与View之间具有镶嵌的视图上,而且视图上必须为点击可用。当一个点击事件产生后,它的传递过程遵循如下顺序:Ac
Fragment实现onTouchEvent事件监听
http://blog.csdn.net/sweetvvck/article/details/38409785里面有介绍, 但是有时候会出现java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity. 只要把public class Main
async、defer与DOMContentLoaded的执行先后关系
摘自:点击打开链接一、HTML解析过程与DOMContentLoaded触发时机我们已经知道DOMContentLoaded的触发时间为:当 HTML文档被加载和解析完成。那么我们还需要理解HTML的解析过程。此处我们先只考虑同步js的情况。1.在既没有CSS也没有JS的情况下,HTML文档的解析过程为:DOMContentLoaded事件的触发时机为:HTML解析为DOM之后。2.有CSS无JS...
Fragment中onTouchEvent的实现
众所周知,Android开发中可以通过onTouchEvent()实现对手势触摸的监听,通过监听实现一些特殊的要求实现我们想要的效果,在Activity中当然没问题,直接重写onTouchEvent即可。但是在Fragemnt类中呢?Fragment类中是没有onTouchEvent()方法的,这怎么实现呢?我的开发中就遇到过这种问题。百思不得姐,无奈,百度了一下,发现好多的文章都提供了在Frag
什么会在main函数之前执行
1、可以定义一个全局对象,这时会调用该类的构造函数。 #include #include using namespace std; class A { public: A() { cout << "A construct 1!" << endl; } }; static A a;//定义全局对象 int main(int argc, char *argv[])
onTouch和onTouchEvent方法调用顺序
安卓中view和viewGroup在点击的时候有两个方法,onTouch和onTouchEvent onTouch是设置了onTouchLisenter之后的回调方法。如果设置了onTouchLisenter就会调用ontouch方法,同时onTouchEvent方法不会再被调用 如果没有设置onTouchLisenter,就会调用onTouchEvent。就是说ontouch的优先级比onT
Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()
Android中触摸事件传递过程中最重要的是dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()方法。这个是困扰初学者的问题之一,我开始也是。这里记录一下dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()的处理过程,以供记忆。