一:enable与clickable对点击事件的影响:
1.View的Dispatchtouchevent 中 首先调用onTouch(返回值为true则消耗事件),未消耗事件则调用onTouchEvent 。onTouchEvent 首先调用onTouchDelegate(需传入一个Rect参数,可以控制点击范围) ,未消耗事件则调用 onClick(只在MotionEvent.ACTION_UP时触发) 。
2.Disenable时onTouch不执行,onTouchEvent执行但是仅仅返回值,如果clickable返回true消耗事件,disaclickable返回false。其中的onTouchDelegate,onClick和onLongClick都不会执行。
3.enable,disclickable时onTouch, onTouchDelegate能执行,onClick仅仅返回false。
总结:enable为false时任何触摸或点击事件都不会执行,但如果clickable为true则消耗掉该次点击事件. clickable只影响onClick,onLongClick,不影响onTouch, onTouchDelegate.
注意:在setOnClickListen时,会将控件的clickable恢复为true,这里要注意一下,不要又setOnClickListen,又在xml中设置clickable为false.
二:Focusable对点击事件的影响
在Android开发中对于现在的手机来说,都是触摸模式(TocuMode),就是当你触摸一个控件的时候,这个控件会获取焦点。注意:有些控件是默认不具有触摸获取焦点的功能的(Button、TextView、LinearLayout等等这些控件是默认没有触摸获取焦点功能的,为什么会有这种问题呢?原因是这些控件有时候可能会想要先响应点击事件,如果触摸获取焦点功能打开后,当你点一下,默认是不会调用点击事件的,这个时候会先让这个控件获取焦点)EditText是默认有触摸获取焦点功能的,并将第一抢先获取焦点。这就解释了为什么当一个页面有EditText的时候,我们进入的时候默认有光标,键盘弹出,这就是焦点在这EditText上面。
就像上面说的那些控件(Button、TextView LinearLayout等等这些默认没有触摸获取焦点功能的控件),当你点击它的时候,它也不会获取焦点也就是调用 isFocused()方法的时候返回的也是false,这个时候默认的是触发到它的点击事件。如果你配置了focusableInTouchMode的话这个时候这些控件才会获取焦点,而这个时候是不会触发点击事件的,触发的是 OnFocusChangeListener。这个时候获取了焦点,当你在点击的时候才会触发点击事件。
而且你在Button、TextView、LinearLayout等等这些控件的xml中设置focusable为true也没用,因为它们在创建的时候在代码里又会置为false的。实质上在触摸模式下的focus的功能大部分情况都没有与点击事件关联起来。
三:ViewGroup中android:descendantFocusability用法简析
开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,当item中有能获取焦点的控件时,问题就出现了,可能会发生点击每一个item的时候没有反应。
这时候就可以使用descendantFocusability来解决啦,API描述如下:
该属性是当一个为view获取焦点时,定义viewGroup和其子控件两者之间的关系。
属性的值有三种:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
通常我们用到的是第三种,即在Item布局的根布局加上android:descendantFocusability=”blocksDescendants”的属性就好了,
我们通过源码来看一下解决这问题的原理。
下面是ListView中触发点击事件,可见listview要认为!child.hasFocusable()时才会触发点击事件
if (inList && !child.hasFocusable()) {
if (this.mPerformClick == null) {
this.mPerformClick = new AbsListView.PerformClick(null);
}
……………………………………………………
}
而ViewGroup中FOCUS_BLOCK_DESCENDANTS的作用能不add子view的 focusable。
if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
if (shouldBlockFocusForTouchscreen()) {
focusableMode |= FOCUSABLES_TOUCH_MODE;
}
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
child.addFocusables(views, direction, focusableMode);
}
}
}
所以listview这里只是自己增加了focus对点击事件的处理,并不能代表ViewGroup与View之间的点击事件处理方式。