在焦点模式下,当我们按下方向键的时候,android系统就会调用当前焦点控件的focusSerach方法,找到下一个焦点的控件,并把焦点赋给它。
一般情况下,Android系统查找的焦点,是以中心点为依据(没有看源码,从平常操作的感觉是这样),按指定的方向,找到距离当前控件中心点最近的下一个控件。
通常这正是我们需要的焦点顺序。但是,凡是总有例外。有时候我们想要的焦点顺序和系统查找的顺序不一致,这时候,有什么办法吗?
以下介绍两种方法:
一、当我们明确知道,下一个获取焦点的控件时,可以调用setNextFocusUpId()的方法(当然,还有对应的setNextFocusDownId,setNextFocusLeftId,setNextFocusRightId等方法)。系统查找下一个焦点的时候,就会返回我们设置id的那个控件。
二、当我们无法知道下一个控件的ID的时候,可以重写focusrSearch方法。
这种方法就比较复杂了,需要根据实际情况来改写,当然,需要了解focusSearch的原理,才能改写。
ok,开始分析focusSearch的原理。
来看一下focusSearch的时序图:
分为以下步骤:
1、按下方向键的时候,系统就会调用到当前焦点的searchFocus(int direction)方法。源码如下:
public View focusSearch(@FocusRealDirection int direction) {
if (mParent != null) {
return mParent.focusSearch(this, direction);
} else {
return null;
}
}
2、从上面代码第三句代码中可以看到,它会调用parent(ViewGroup)的focusSearch(View focused,int ditection)的方法。源码如下:
public View focusSearch(View focused, int direction) {
if (isRootNamespace()) {
// root namespace means we should consider ourselves the top of the
// tree for focus searching; otherwise we could be focus searching
// into other tabs. see LocalActivityManager and TabHost for more info
return FocusFinder.getInstance().findNextFocus(this, focused, direction);
} else if (mParent != null) {
return mParent.focusSearch(focused, direction);
}
return null;
}
3,先看上面代码第8行,如果当前节点还不是根节点的话,就调用父节点的focusSearch继续查找,直到根节点为止(第6行)。在根节点调用
findNextFocus(ViewGroup root, View focused, int direction)的方法,并把根节点赋值给它。
public final View findNextFocus(ViewGroup root, View focused, int direction) {
return findNextFocus(root, focused, null, direction);
}
private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
View next = null;
if (focused != null) {
next = findNextUserSpecifiedFocus(root, focused, direction);
}
if (next != null) {
return next;
}
ArrayList<View> focusables = mTempList;
try {
focusables.clear();
root.addFocusables(focusables, direction);
if (!focusables.isEmpty()) {
next = findNextFocus(root, focused, focusedRect, direction, focusables);
}
} finally {
focusables.clear();
}
return next;
}
第二段代码的第4行,就是先查找用户设置的nextFocus。即第一种方法设置的setNextFocusUpId等。
接下来就是按照算法查找下一个焦点,现在还没有必要完全了解。
从上面的分析中,有两个重点需要注意:
1、focusSearch只是查找下一个获取焦点的控件,但改控件还未获取焦点(需要调用requestFocus后才能获取焦点)。
所以,可以充值focusSearch的方法,来选择自己需要的下一个焦点。
2、注意看这个方法:FocusFinder.getInstance().findNextFocus(ViewGroup root, View focused, int direction).它的第一个参数是ViewGruop,所以,如果你需要限定在某个ViewGruop中查找控件,就可以在focusSeach中调用这个方法。