一.初遇问题
在做项目的过程中遇到了一个问题,有一个可以显示两个TextView外加一个RadioButton 的ListView,然后给ListView 设置了OnItemClickListener,
mListView.setOnItemClickListener(mOnItemClickListener);
点击Listview的列表确没有任何反应,onItemClick方法中的log也没有打印。
二.分析原因
是什么导致ListView的Item点击事件失效呢?
首先我们的Item中有一个可以点击的RadioButton,大家都知道RadioButton可以点击,可以点击就涉及到焦点的获取,诸如 ImageButton、CheckBox、RadioButton之类的控件本身在初始化的时候就赋予了焦点,我们来看一下ImageButton的构造函数
public ImageButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setFocusable(true);
}
/**
* Set whether this view can receive the focus.
*
* Setting this to false will also ensure that this view is not focusable
* in touch mode.
*
* @param focusable If true, this view can receive the focus.
*
* @see #setFocusableInTouchMode(boolean)
* @attr ref android.R.styleable#View_focusable
*/
public void setFocusable(boolean focusable) {
if (!focusable) {
setFlags(0, FOCUSABLE_IN_TOUCH_MODE);
}
setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK);
}
setFlags的代码比较长这里就不再贴出来,感兴趣的同学可以自行查阅,总之这类子控件初始化后会被赋予焦点,从而抢夺父容器的焦点导致父容器点击失效。
三.解决办法
当查阅相关api可以发现
ViewGroup的api中有一个setDescendantFocusability的api涉及到了ViewGroup的焦点处理。
void | setDescendantFocusability(int focusability) Set the descendant focusability of this view group. |
该方法的参数是int类型的值,我们往回看会看到三个跟焦点相关的int类型的常量
int | FOCUS_AFTER_DESCENDANTS This view will get focus only if none of its descendants want it. |
int | FOCUS_BEFORE_DESCENDANTS This view will get focus before any of its descendants. |
int | FOCUS_BLOCK_DESCENDANTS This view will block any of its descendants from getting focus, even if they are focusable. |
三个常量的大致意思是
FOCUS_AFTER_DESCENDANTS:当前Viewgroup只有在它的所有子控件都不需要焦点时才获得焦点。
FOCUS_BEFORE_DESCENDANTS:当前ViewGroup将先于其子控件而获得焦点。
FOCUS_BEFORE_DESCENDANTS:当前ViewGroup将会拦截其子控件的焦点,即使它的子控件可以自动获得焦点。
显而易见我们这里的RadioButton是自动获取焦点的类型,所以我们只要在这里给我们的item设置setDescendantFocusability(ViewGroup. FOCUS_BEFORE_DESCENDANTS)就可以解决我们的item无法点击的问题了。
当然我们也可以在布局文件中设置来解决此问题。
相关的api是
android:descendantFocusability
Defines the relationship between the ViewGroup and its descendants when looking for a View to take focus.
Must be one of the following constant values.
Constant | Value | Description |
---|---|---|
beforeDescendants | 0 | The ViewGroup will get focus before any of its descendants. |
afterDescendants | 1 | The ViewGroup will get focus only if none of its descendants want it. |
blocksDescendants | 2 | The ViewGroup will block its descendants from receiving focus. |
This corresponds to the global attribute resource symbol descendantFocusability
.
我们只需要在Item布局的根节点加上 android:descendantFocusability=”blocksDescendants”属性就可以了。
四.总结
遇到问题时除了Google上直接搜资料之外,时间不紧急的话最好还是多查阅Google的原版文档,多看看相关的源码逻辑,肯定会受益匪浅。