1:View的事件响应机制(控件:如TextView,ImageView,Button等)
在执行onTouchListener方法时候,(view这里代表为控件)
view.setOnTouchListener (new OnTouchListener() {
@Override
public boolean onTouch( View v, MotionEvent event) {
return false ;
}
});
事件分发的时候会执行publicboolean dispatchTouchEvent(MotionEvent event)
a:先进行if判断
if (li != null && li .mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li .mOnTouchListener .onTouch (this, event)) {
return true ;
}
return onTouchEvent(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
public boolean onInterceptTouchEvent( MotionEvent ev) {
return true ;
}
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:拦截事件
自定义控件
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout (Context context , AttributeSet attrs ) {
super(context , attrs );
}
@Override
public boolean onInterceptTouchEvent( MotionEvent ev) {
return true ;
}
}
MainActivity
public class MainActivity extends Activity {
private LinearLayout my_ll;
private Button button;
private TextView textView;
@Override
protected void onCreate( 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(new OnTouchListener() {
@Override
public boolean onTouch( View v, MotionEvent event) {
System .out.println( "Linearlayout:"+event .getAction ());
return true ;
}
});
textView. setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch( View v, MotionEvent event) {
System .out.println( "TextView:"+event .getAction ());
return false ;
}
});
button. setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch( View v, MotionEvent event) {
System .out.println( "Button:"+event .getAction ());
return false ;
}
});
// 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了。