onTouch事件试验(覆写onTouchEvent方法,同时设置onTouchListener)

xml布局文件

<</span>RelativeLayout 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" >

    <</span>com.example.shijian.MyButton
        android:id="@+id/mybutton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="测试按钮"
        />

</</span>RelativeLayout>

自定义Button

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Button;

public class MyButton extends Button
{
    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        super.onTouchEvent(event);
        int ea=event.getAction();
//           Log.i("TAG", "Touch:"+ea);
           switch(ea)
           {
           case MotionEvent.ACTION_DOWN:
           {
               Log.v("-MyButton-","------ACTION_DOWN-----");
               return true;
//               break;
           }
           case MotionEvent.ACTION_MOVE:
           {
               Log.v("-MyButton-","------ACTION_MOVE-----");
               break;
           }
           case MotionEvent.ACTION_UP:
           {
               Log.v("-MyButton-","------ACTION_UP-----");
               break;
           }
    }return false; 

    }

}

MainActivity

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class MainActivity extends Activity{

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

        MyButton mybutton = (MyButton)findViewById(R.id.mybutton);
        mybutton.setOnTouchListener(new OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {
                int ea=event.getAction();
//                   Log.i("TAG", "Touch:"+ea);
                   switch(ea)
                   {
                   case MotionEvent.ACTION_DOWN:
                   {
                       Log.v("-onTouchListener-","------ACTION_DOWN-----");
                       break;
//                       return true;
                   }
                   case MotionEvent.ACTION_MOVE:
                   {
                       Log.v("-onTouchListener-","------ACTION_MOVE-----");
                       break;
//                       return true;
                   }
                   case MotionEvent.ACTION_UP:
                   {
                       Log.v("-onTouchListener-","------ACTION_UP-----");
                       break;
//                       return true;
                   }

            }
                return false;
            }
        });
    }

}

试验结果:

一、首先固定MyButton中OnTouchEvent方法的所有返回都为false,设置OnTouchListener中:

1)所有返回均为false:

且Button的状态保持按下,即ACTION_UP没有执行

结论:这里用《疯狂android讲义》中的话:几乎所有基于回调的事件处理方法都有一个boolean类型的返回值,该返回值用于表示该处理方法是否能完全处理该事件:

  *如果处理事件的回调方法返回true,表明该处理方法已完全处理该事件,该事件不会传播出去。

  *如果处理事件的回调方法返回false,表明该处理方法并未完全处理该事件,该事件回传播出去。

从Log输出可以看出,Listener最先触发了Touch事件,由于返回了false,事件传播了出去,所以MyButton的方法也触发了Touch事件。但是Touch事件是由ACTION_DOWN,ACTION_MOVE,ACTION_UP三个事件组成,为什么只打印了ACTION_DOWN呢?从图中的Button的状态来看,ACTION_UP确实没有执行,那么ACTION_MOVE呢?也没有执行,至于为什么,先卖个关子,会在后面解释清楚。

2)ACTION_DOWN返回true,其他返回false:

3)ACTION_DOWN和ACTION_MOVE返回true,其他返回false:

4)ACTION_DOWN和ACTION_UP返回true,其他返回false:

5)ACTION_MOVE和ACTION_UP返回true,其他返回false:

结果与1)完全相同

错误的结论:试验做到这里,我认为大概的结论应该是:

  Listener中的ACTION_DOWN若返回true,会发生

  1、ACTION_DOWN不会扩散出去,所以MyButton的OnTouchEvent方法不会触发ACTION_DOWN。

  2、Listener会接受后续的事件,所以Listener的Log会输出ACTION_MOVE和ACTION_UP。

  Listener中的ACTION_DOWN若返回false,会发生

  1、ACTION_DOWN会扩散出去,所以MyButton的OnTouchEvent方法会触发ACTION_DOWN。

  2、Listener不会接受后续的事件,所以Listener的Log不会输出ACTION_MOVE和ACTION_UP。

但是,这些都是在——固定MyButton中OnTouchEvent方法的所有返回都为false——这一前提下,MyButton中OnTouchEvent的事件都是从Listener传递过来的,到底MyButton中OnTouchEvent方法的返回值对结果有没有影响呢?下面会有结果。

6)所有返回true

二、固定OnTouchListener的返回全为false,OnTouchEvent方法的返回值:

1)ACTION_DOWN为true,其他全为false

这个结果把之前的结论彻底推翻了。

猜想:事件是否完全处理会影响到后续事件

     前面说过:*如果处理事件的回调方法返回true,表明该处理方法已完全处理该事件,该事件不会传播出去。

          *如果处理事件的回调方法返回false,表明该处理方法并未完全处理该事件,该事件回传播出去。

     但是传播出去后呢?当传播到下一个地方,又会进行判断,true就完全处理事件,不再传播,如果又是false呢?

     从ACTION_DOWN到ACTION_UP是一个连续的事件,这个连续事件中有ACTION_DOWN,ACTION_MOVE,ACTION_UP三个子事件。android的事件传播,是一种由下向上的冒泡传播,子控件不处理,就传到父控件。如果子事件被完全处理了(被消费了),则下一个子事件才能开始,否则,这个子事件将堵塞(例如所有的控件都不处理),后续的子事件将无法进入处理流程。

三、OnTouchListener的ACTIONO_DOWN返回false,其他两个返回true,OnTouchEvent方法的ACTION_DOWN返回true,其他两个false:

Button的状态:

这一试验说明猜想成功了一次:

  由于OnTouchListener的ACTION_DOWN返回false,则不处理继续传播,到OnTouchEvent方法,返回true,表示消费了ACTION_DOWN事件,则ACTION_MOVE事件得以进入流程。

  OnTouchListener的ACTION_MOVE返回true,表示已经消费了ACTION_MOVE事件,则ACTION_UP事件得以进入流程。ACTION_MOVE事件不再传播,所以Log日志中,OnTouchEvent方法没有ACTION_MOVE输出。

  OnTouchListener的ACTION_UP返回true,表示已经消费了ACTION_UP事件,不再传播,所以Log日志中,OnTouchEvent方法没有ACTION_UP输出。

  由于OnTouchEvent方法仅仅执行了ACTION_DOWN,所以按钮的状态为“一直按下”。

四、OnTouchListener的ACTIONO_UP返回true,其他两个返回false,OnTouchEvent方法的ACTION_DOWN返回true,其他两个false:

Button的状态:

看到了吗,将上个试验中OnTouchListener的ACTIONO_UP改为true,其他不变,按钮就恢复了,从Log也看到OnTouchEvent方法的ACTION_UP输出了。

时间: 2024-10-12 18:02:24

onTouch事件试验(覆写onTouchEvent方法,同时设置onTouchListener)的相关文章

继承BaseAdapter覆写getView()方法解析

当我们继承BaseAdapter自定义适合自己使用的Adapter时候,不可避免的要覆写getView()方法.自己在分析蓝牙4.0官方源代码遇到这个问题,分析了几遍,有所领悟,参考了这篇博文http://blog.csdn.net/pkxiuluo01/article/details/7380974,现结合蓝牙4.0官方的这部分代码将getView()解析一下. //当界面每显示出来一个item时,就会调用该方法,getView()有三个参数,第一个参数表示该item在Adapter中的位置:

java覆写equals方法

何时需要重写equals() 当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念). object规范规定,如果要重写equals(),也要重写hashcode() 如何覆写equals() 覆写equals方法 1  使用instanceof操作符检查“实参是否为正确的类型”. 2  对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值. 3. 对于非float和double类型的原语类型域,使用==比较: 4  对于对象引用域,递归调用equals方法: 5  对于flo

覆写equals方法为什么需要覆写hashCode方法

覆写equals方法必须覆写hashCode方法,是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢? void test() { // Person类的实例作为Map的key Map<Person, Object> map = new HashMap<Person, Object>(); map.put(new Person("张三"), new Object()); // Person类的实例作为List的元素 List<P

覆写toString方法 Java提供的默认toString方法不好用

还有一个问题的是包管理,并没有官方最佳管理方案,在go的世界里存在大量的自制解决方案.go语言的包是没有中央库统一管理的,通过使用go get命令从远程代码库(github.com,goolge code 等)拉取,直接跳过中央版本库的约束,让代码的拉取直接基于源代码版本控制库,开发者间的协同直接依赖于源代码的版本控制.直接去除了库版本的概念.没有明显的包版本标识,感觉还是有点不适应,官方的建议是把外部依赖的代码全部复制到自己可控的源代码库中,进行同意管理.从而做到对依赖包的可控管理. R软件功

UINavgationController中覆写preferredStatusBarStyle方法不执行的问题

#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } -(UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleDefault; } @end 如果viewController不是在 UINa

review——C# (6)虚方法和覆写方法

FROM P125 在上一节中看到,当使用基类引用访问派生类对象时,得到的是基类的成员.虚方法可以使基类的引用访问"升至"派生类内. 可以使用基类引用调用派生类(derived class)的方法,只需满足下列条件: □派生类的方法和基类的方法有相同的签名和返回类型 □基类的方法使用virtual标注 □派生类的方法使用override标注 使用方法如下例: 1 class MyBaseClass //基类 2 { 3 virtual public void Print(); 4 }

方法的覆写

方法的覆写 类和父类有相同的方法,那么类中方法的访问权限不能比父类中对应方法的访问权限严格,这就叫方法的覆写,一般称之为类覆写了父类中的某个方法 覆写方法的作用:对于一个类,向上转换后(把类的实例化对象赋值给类的父类的对象),通过该父类的对象直接访问该父类的对象的本类部分中被类所覆写的方法时,将自动访问跳转到类中对应的覆写的方法 static方法的覆写不起覆写作用,原因现阶段只能解释为Java就是这样设计的 package test1; public class Test1 { public s

Java中方法的覆写

所谓方法的覆写override就是子类定义了与父类中同名的方法,但是在方法覆写时必须考虑权限,即被子类覆写的方法不能拥有比父类方法更加严格的访问权限. 修饰符分别为public.protected.default.private.他们的访问权限如下图所示. 用public修饰的类在本类.同包.子类.其他包中互相访问都是可以的. 用protected修饰的类在本类.同包.子类中互相访问都是可以的,protected不可以在包外没有继承关系的类中互相访问. 就说明用default修饰的类在本类.同包

关于方法的继承和覆写

* 关于方法的覆写: *   关于方法的重写和覆盖的前提条件: *     子类继承父类,就继承了父类的所有方法和属性,就相当于把父类的代码完全复制一份到子类,只是相当于 *     我们子类中可以添加新的方法和属性,同时也可以扩展改写继承自父类的方法 *     1 什么时候方法要进行重写? *     如果父类中的方法已经无法满足子类的要求,需要将父类中的方法进行重新写一遍 *     2.子类如果重写父类中的方法之后,这类对象一定调用重写之后的方法 *     3 发生方法覆盖的条件: *