1、关于控件点击事件
Android中TextView、Button、ImageView等等控件都可以实现点击事件,下面以TextView和Button举例
view.setOnTouchListener(new OnTouchListener() {
<span style="white-space:pre"> </span>@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return false;
}
});
TextView与Button分别实现OnTouchListener监听事件,两个控件分别进行一次点击事件执行如下:
TextView的onTouch方法执行一次
Button的onTouch方法执行两次
修改一:将reutrn false 改为 true
TextView的onTouch方法执行两次
Button的onTouch方法执行两次
修改二:两个控件分别实现点击事件
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
运行结果:TextView的onTouch方法执行两次
Button的onTouch方法执行两次
2、原因分析
当用户触摸屏幕时,系统会把一系列的触摸事件封装成一个MotionEvent对象,然后通过dispatchTouchEvent进行事件分发,关于事件分发,下面将会提到。onTouch()方法之所以被执行,是因为View中dispatchTouchEvent()会调用onTouch()方法
而进行事件分发时判断
是否实现了OnTouchListener接口的onTouch方法
是否可被点击
onTouch()方法返回值
以上会造成onTouch()方法至少调用一次调用,如果返回true表示消费此事件,将会执行第二次
如果onTouch()方法此时返回false,此时是否执行第二次,由是否可点击决定,View的部分源码如下
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
return true;
}
if (onTouchEvent(event)) {
return true;
}
onTouchEvent方法会判断该控件是否可点击,而Button默认就是可点击的,所以导致前面Button未作任何设置都不会影响其onTouch方法的执行
public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
只要设置了onClick方法,那么就会被设置为可点击,该控件就会消费后面的事件3、事件的分发
Android的事件通过分发-拦截-处理几个步骤,通过FrameLayout、LinearLayout、TextView三个控件来了解分发的次序
public boolean dispatchTouchEvent(MotionEvent event){
L.i("---> start");
boolean b = super.dispatchTouchEvent(event);
L.i("---> end");
return b;
}
1、FrameLayout
|-- LinearLayout
|-- TextView
点击事件执行结果
点击FrameLayout: FrameLayout --->start --->end
点击LinearLayout: FrameLayout start ---> LinearLayout start ---> LinearLayout end ---> FrameLayout end
点击TextView:FrameLayout start ---> LinearLayout start ---> TextView start ---> TextView end --- >LinearLayout end ---> FrameLayout end
2、FrameLayout| -- LinearLayout
| -- TextView
点击事件执行结果
FrameLayout与LinearLayout结果与上面相同
TextView:FrameLayout start ---> TextView start ---> TextView end ---> LinearLayout start ---> LinearLayout end ---> FrameLayout end
FrameLayout发现子View按倒序进行事件分发 ,从源码得知:for(int i=count-1;i>=0;i--)