以下所涉及的焦点部分,只是按键移动部分,不明确包含Touch Focus部分
控件的下一个焦点是哪?
当用户通过按键(遥控器等)触发焦点切换时,事件指令会通过底层进行一系列处理。 在ViewRootImpl.java中有一个方法,deliverKeyEventPostIme(...),因为涉及到底层代码,所以没有详细的跟踪分析此方法的调用逻辑,根据网上的资料,按键相关的处理会经过此方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 |
private
void deliverKeyEventPostIme(QueuedInputEvent q) { ... // Handle automatic focus changes. if
(event.getAction() == KeyEvent.ACTION_DOWN) { int
direction = 0 ; switch
(event.getKeyCode()) { case
KeyEvent.KEYCODE_DPAD_LEFT: if
(event.hasNoModifiers()) { direction = View.FOCUS_LEFT; } break ; case
KeyEvent.KEYCODE_DPAD_RIGHT: if
(event.hasNoModifiers()) { direction = View.FOCUS_RIGHT; } break ; ... } if
(direction != 0 ) { View focused = mView.findFocus(); if
(focused != null ) { View v = focused.focusSearch(direction); if
(v != null
&& v != focused) { ..... if
(v.requestFocus(direction, mTempRect)) { ...finishInputEvent(q, true ); return ; } } ... } } |
1
2 |
View v = focused.focusSearch(direction); v.requestFocus(direction, mTempRect) |
在具体分析前,首先我们先明确下相关变量的定义
View mView : 主体View[DecorView]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
//一般把主View“DecorView”添加到WindowManagerImpl中(通过addView) //WindowManagerImpl.java private
void addView(View view...) { ViewRootImpl root; root = new
ViewRootImpl(view.getContext()); ... root.setView(view, wparams, panelParentView); ... }<br> //ViewRootImpl.java public
void setView(View view....) { synchronized
( this ) { if
(mView == null ) { mView = view; ... } ... } } |
View focused :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 |
View focused = mView.findFocus();<br> //PhoneWindow.java private
final class DecorView extends
FrameLayout implements
RootVie.... { ... }<br> //FrameLayout.java public
class FrameLayout extends
ViewGroup { ... }<br> //ViewGroup.java //mFocused记录的是当前被焦点选中的view @Override public
View findFocus() { if
(DBG) { System.out.println( "Find focus in "
+ this + ": flags=" + isFocused() + ", child="
+ mFocused); } if
(isFocused()) { return
this ; } if
(mFocused != null ) { return
mFocused.findFocus(); } return
null ; } |
在明确的相关变量后,我们开始View v = focused.focusSearch(direction)的具体分析.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
//View.java public View focusSearch( int
direction) { //如果存在父控件,则执行父控件的focusSearch方法 if
(mParent != null ) { return
mParent.focusSearch( this , direction); } else
{ return
null ; } } //ViewGroup.java public
View focusSearch(View focused, int
direction) { //判断是否为顶层布局,若是则执行对应方法,若不是则继续向上寻找,说明会从内到外的一层层进行判断,直到最外层的布局为止 if
(isRootNamespace()) { return
FocusFinder.getInstance().findNextFocus( this , focused, direction); } else
if (mParent != null ) { return
mParent.focusSearch(focused, direction); } return
null ; } |
说明在这个过程中,其实是从里层开始一直遍历到最外层布局,然后在最外层布局将处理交给了FocusFinder中的方法.
1 |
FocusFinder.getInstance().findNextFocus( this , focused, direction); |
1
2
3
4 |
//FocusFinder.java public final View findNextFocus(ViewGroup root, View focused, int
direction) { return
findNextFocus(root, focused, null , direction); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 |
//FocusFinder.java 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; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 |
//FocusFinder.java private
View findNextUserSpecifiedFocus(ViewGroup root, View focused, int
direction) { // check for user specified next focus View userSetNextFocus = focused.findUserSetNextFocus(root, direction); if
(userSetNextFocus != null
&& userSetNextFocus.isFocusable() && (!userSetNextFocus.isInTouchMode() || userSetNextFocus.isFocusableInTouchMode())) { return
userSetNextFocus; } return
null ; }<br> //View.java View findUserSetNextFocus(View root, int
direction) { switch
(direction) { case
FOCUS_LEFT: if
(mNextFocusLeftId == View.NO_ID) return
null ; return
findViewInsideOutShouldExist(root, mNextFocusLeftId); case
FOCUS_RIGHT: if
(mNextFocusRightId == View.NO_ID) return
null ; return
findViewInsideOutShouldExist(root, mNextFocusRightId); case
FOCUS_UP: if
(mNextFocusUpId == View.NO_ID) return
null ; return
findViewInsideOutShouldExist(root, mNextFocusUpId); case
FOCUS_DOWN: if
(mNextFocusDownId == View.NO_ID) return
null ; return
findViewInsideOutShouldExist(root, mNextFocusDownId); case
FOCUS_FORWARD: if
(mNextFocusForwardId == View.NO_ID) return
null ; return
findViewInsideOutShouldExist(root, mNextFocusForwardId); case
FOCUS_BACKWARD: { if
(mID == View.NO_ID) return
null ; final
int id = mID; return
root.findViewByPredicateInsideOut( this , new
Predicate<View>() { @Override public
boolean apply(View t) { return
t.mNextFocusForwardId == id; } }); } } return
null ; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 |
//FocusFinder.java private
View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int
direction, ArrayList<View> focusables) { if
(focused != null ) { if
(focusedRect == null ) { focusedRect = mFocusedRect; } // fill in interesting rect from focused focused.getFocusedRect(focusedRect); root.offsetDescendantRectToMyCoords(focused, focusedRect); } else
{ if
(focusedRect == null ) { focusedRect = mFocusedRect; // make up a rect at top left or bottom right of root switch
(direction) { case
View.FOCUS_RIGHT: case
View.FOCUS_DOWN: setFocusTopLeft(root, focusedRect); break ; case
View.FOCUS_FORWARD: if
(root.isLayoutRtl()) { setFocusBottomRight(root, focusedRect); } else
{ setFocusTopLeft(root, focusedRect); } break ; case
View.FOCUS_LEFT: case
View.FOCUS_UP: setFocusBottomRight(root, focusedRect); break ; case
View.FOCUS_BACKWARD: if
(root.isLayoutRtl()) { setFocusTopLeft(root, focusedRect); } else
{ setFocusBottomRight(root, focusedRect); break ; } } } } switch
(direction) { case
View.FOCUS_FORWARD: case
View.FOCUS_BACKWARD: return
findNextFocusInRelativeDirection(focusables, root, focused, focusedRect, direction); case
View.FOCUS_UP: case
View.FOCUS_DOWN: case
View.FOCUS_LEFT: case
View.FOCUS_RIGHT: return
findNextFocusInAbsoluteDirection(focusables, root, focused, focusedRect, direction); default : throw
new IllegalArgumentException( "Unknown direction: "
+ direction); } } |
查找焦点的过程,主要是从View的focusSearch(...)方法开始,从当前焦点开始逐层往外,最终在最外层布局执行FocusFinder中的核心方法来获得下个焦点所在的视图view.
如果需要指定跳转,可以在逐层focusSearch(...)的时候,返回特定的view
[Android学习笔记]理解焦点处理原理的相关记录,布布扣,bubuko.com
原文:http://www.cnblogs.com/myzh/p/3664544.html