1:View的事件响应机制(控件:如TextView,ImageView,Button等)

在执行onTouchListener方法时候,(view这里代表为控件)

view.setOnTouchListener(newOnTouchListener(){

@Override

publicbooleanonTouch(View v,MotionEvent event){

returnfalse;

}

});

事件分发的时候会执行publicbooleandispatchTouchEvent(MotionEvent event)

a:先进行if判断

if(li!=null&&li.mOnTouchListener!=null&&(mViewFlags&ENABLED_MASK)==ENABLED

&&li.mOnTouchListener.onTouch(this,event)){

returntrue;

}

returnonTouchEvent(event);

li就是OnTouchListener的实现类,不为null,第二个条件判断控件是否可用,一般恒成立,主要就看第三个条件了。

return true:就代表响应所有事件。

return false:就会执行onTouchEvent方法了。

b:setOnTouchListener方法返回了false

在onTouchEvent方法中,如果控件具备点击事件,在action_up中回调执行onClick的点击事件,并且返回true,响应所有事件。如果控件不具备点击事件,就会返回false,也进入不了switch中。

2:ViewGroup的事件响应机制

ViewGroup的事件响应机制主要分为2部分:1:ViewGroup拦截了事件,2:ViewGroup没有拦截事件

/*

* return true拦截了事件

* return false没有拦截事件,往内部传递

*/

@Override

publicbooleanonInterceptTouchEvent(MotionEvent ev){

returntrue;

}

1:拦截了事件:

那么ViewGroup就会去处理事件,在源码中最后还是调用View的dispatchTouchEvent方法,由其决定是否响应,onTouchEventListener中return了true,就响应了事件,return了false,那么就去判断当前控件(布局)是不是可以被点击,测试了一次ListView,ListView点击的时候响应了事件。ListView无论是不是中断,都会由View的dispatchTouchEvent方法决定,ListView可以被点击。

2:没有拦截事件:

最外层的ViewGroup先捕获到事件,计算出点击的位置,遍历自己的孩子,传递给对应的ViewGroup,然后第二层是不是拦截啊?不拦截,继续遍历,找到具体点击的地方的控件view。

控件view会去通过View的dispatchTouchEvent方法的返回值判断是不是响应了点击事件,return true;响应了,那么结束了。如果return false;了没有响应,那么事件会向回传递,自己的父亲回去尝试响应了。同样,通过dispatchTouchEvent来进行决定是不是响应了事件。


示例代码:


1:拦截事件


自定义控件

publicclassMyLinearLayoutextendsLinearLayout{


publicMyLinearLayout(Context context,AttributeSet attrs){

super(context,attrs);

}

@Override

publicbooleanonInterceptTouchEvent(MotionEvent ev){

returntrue;

}

}

MainActivity

publicclassMainActivityextendsActivity{


privateLinearLayoutmy_ll;

privateButtonbutton;

privateTextViewtextView;

@Override

protectedvoidonCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

my_ll=(LinearLayout)findViewById(R.id.my_ll);

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

textView=(TextView)findViewById(R.id.text);

my_ll.setOnTouchListener(newOnTouchListener(){

@Override

publicbooleanonTouch(View v,MotionEvent event){

System.out.println("Linearlayout:"+event.getAction());

returntrue;

}

});

textView.setOnTouchListener(newOnTouchListener(){

@Override

publicbooleanonTouch(View v,MotionEvent event){

System.out.println("TextView:"+event.getAction());

returnfalse;

}

});

button.setOnTouchListener(newOnTouchListener(){

@Override

publicbooleanonTouch(View v,MotionEvent event){

System.out.println("Button:"+event.getAction());

returnfalse;

}

});

//my_ll.setOnClickListener(new OnClickListener() {

//

//@Override

//public void onClick(View v) {

//System.out.println("Linearlayout");

//}

//});

}

}

分析:my_ll不再向里面的Button和TextView传递了,自己处理,自己在my_ll.setOnTouchListener中返回了false,my_ll又不具备点击事件,当然就只能打印出LineraLayout::0了,如果我们给其设置了点击事件,那么当然会打印出down,up,click三者了。my_ll.setOnTouchListener中返回了true,自己也进行了处理,不过就只能打印出down,up了。


2:不拦截事件


分析:点击button,响应了事件,其可以点击,肯定会响应。点击TextView时候,其默认没有点击事件,只能打印down了,然后不响应,往回传递,my_ll去响应,my_ll又会通过View的dispatchTouchEvent去处理了。我们这里在my_ll.setOnTouchListener中返回了true的话,肯定会打印如下:TextView的down,MyLinearlayout的down,up了。