public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
return requestFocusNoSearch(direction, previouslyFocusedRect);
private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
// need to be focusable
if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE ||
(mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
// need to be focusable in touch mode if in touch mode
if (isInTouchMode() &&
(FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
return false;
// need to not have any parents blocking us
if (hasAncestorThatBlocksDescendantFocus()) {//判断父视图是否阻止子视图获得焦点
return false;
handleFocusGainInternal(direction, previouslyFocusedRect);//进行具体的焦点获取
return true;
void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
if (DBG) {
System.out.println(this + " requestFocus()");
if ((mPrivateFlags & FOCUSED) == 0) {
mPrivateFlags |= FOCUSED;
if (mParent != null) {
mParent.requestChildFocus(this, this);//第一个参数是child视图,第二个是focused视图,该函数内部进行递归调用
//注意时态,xxxed()和xxx()的区别是,前者是执行完之后回调,后者是在执行前回调
onFocusChanged(true, direction, previouslyFocusedRect);
refreshDrawableState();
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
notifyAccessibilityStateChanged();
一般来说,父视图是ViewGroup,requestChildFocus在ViewGroup中的实现
public void requestChildFocus(View child, View focused) {
if (DBG) {
System.out.println(this + " requestChildFocus()");
if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
return;
// Unfocus us, if necessary
super.unFocus();
// We had a previous notion of who had focus. Clear it.
if (mFocused != child) {
if (mFocused != null) {
mFocused.unFocus();
mFocused = child;
if (mParent != null) {
mParent.requestChildFocus(this, focused);//最终会递归到ViewRoot中的equestChildFocus
ViewRootImpl中的requestChildFocus
public void requestChildFocus(View child, View focused) {
checkThread();//确保在UI线程中
if (mFocusedView != focused) {//其实ViewGroup中已经检查过,mFocusedView一定不是目标焦点视图
mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
scheduleTraversals();//发起View遍历请求
mFocusedView = mRealFocusedView = focused;
if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
+ mFocusedView); view中
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
return requestFocusNoSearch(direction, previouslyFocusedRect);
private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
// need to be focusable
if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE ||
(mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
// need to be focusable in touch mode if in touch mode
if (isInTouchMode() &&
(FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
return false;
// need to not have any parents blocking us
if (hasAncestorThatBlocksDescendantFocus()) {//判断父视图是否阻止子视图获得焦点
return false;
handleFocusGainInternal(direction, previouslyFocusedRect);//进行具体的焦点获取
return true;
void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
if (DBG) {
System.out.println(this + " requestFocus()");
if ((mPrivateFlags & FOCUSED) == 0) {
mPrivateFlags |= FOCUSED;
if (mParent != null) {
mParent.requestChildFocus(this, this);//第一个参数是child视图,第二个是focused视图,该函数内部进行递归调用
//注意时态,xxxed()和xxx()的区别是,前者是执行完之后回调,后者是在执行前回调
onFocusChanged(true, direction, previouslyFocusedRect);
refreshDrawableState();
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
notifyAccessibilityStateChanged();
一般来说,父视图是ViewGroup,requestChildFocus在ViewGroup中的实现
public void requestChildFocus(View child, View focused) {
if (DBG) {
System.out.println(this + " requestChildFocus()");
if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
return;
// Unfocus us, if necessary
super.unFocus();
// We had a previous notion of who had focus. Clear it.
if (mFocused != child) {
if (mFocused != null) {
mFocused.unFocus();
mFocused = child;
if (mParent != null) {
mParent.requestChildFocus(this, focused);//最终会递归到ViewRoot中的equestChildFocus
ViewRootImpl中的requestChildFocus
public void requestChildFocus(View child, View focused) {
checkThread();//确保在UI线程中
if (mFocusedView != focused) {//其实ViewGroup中已经检查过,mFocusedView一定不是目标焦点视图
mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
scheduleTraversals();//发起View遍历请求
mFocusedView = mRealFocusedView = focused;
if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now " + mFocusedView);
view中 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { return requestFocusNoSearch(direction, previouslyFocusedRect); }private boolean requestFocusN...
<
request
Focus
>: 标签用于指定屏幕内的焦点View。
布局资源文件的根节点可以使用容器控件(如LinearLayout、FrameLayout等),也可以使用非容器控件(如:EditText、TextView等)。对于非容器控件,只能在非容器控件标签
中
放<
request
Focus
>标签,表示将当前控件设为焦点。如下代码:
<LinearLayout xmlns:
android
=http://schemas.
android
.com/apk/res/
android
布局资源文件的根节点可以使用容器控件(如LinearLayout、FrameLayout等),也可以使用非容器控件(如:EditText、TextView等)。对于非容器控件,只能在非容器控件标签
中
放标签,表示将当前控件设为焦点。如下代码:
<LinearLa
和 invalidateO的
调用
有点相似,
request
Focus
O也是不能独自完成的,当一个视图想要获取焦点时,
必须请求它的父视图完成该操作,为什么呢?因为父视图知道当前哪个视图正在拥有焦点,如果要进行
焦点切换,则必须先告诉原先的视图放弃焦点,而这些操作所需要的信息是在父视图
中
保存的,所以
request
Focus
()也必须由父视图完成。
该函数有如下三个不同的版本。
•
request
Focus
O:无参数,它被转换成
request
Focus
(View.
FOCUS
__DOWN)。
•
request
方法
request
Focus
()代码如下:
public final boolean
request
Focus
() {
return
request
Focus
(View.
FOCUS
_DOWN);
public final boolean
request
Focus
(int direction) {
return
request
Focus
(direction, null);
public boolean reque
相信很多刚接触
Android
TV开发的开发者,都会被各种焦点问题给折磨的不行。不管是学技术还是学习其他知识,都要学习和理解其
中
原理,碰到问题我们才能得心应手。下面就来探一探
Android
的焦点分发的
过程
。
Android
焦点分发
过程
Android
焦点事件的分发是从ViewRootImpl的processKeyEvent开始的,源码如下: private int processK
今天看到一个需要实现一个点赞的功能。自己想没想明白,后来看了http://blog.csdn.net/nupt123456789/article/details/39432781 这篇博客,才有了思路。特意感谢
这是我要用的ListView的item。要给ListView设置单个刷新,实现点击事件。
1.布局 (不要问我为什么是绝对布局,,我开心)
android
:
2. 通过 XML 属性设置焦点:可以在 XML 文件
中
使用
android
:
focus
able 和
android
:
focus
ableInTouchMode 属性来设置 View 是否可获得焦点,例如:
<EditText
android
:id="@+id/editText"
android
:layout_width="match_parent"
android
:layout_height="wrap_content"
android
:
focus
able="true"
android
:
focus
ableInTouchMode="true" />
3. 通过监听器处理焦点:可以通过设置 View 的 On
Focus
ChangeListener 来监听焦点变化事件,例如:
editText.setOn
Focus
ChangeListener(new View.On
Focus
ChangeListener() {
@Override
public void on
Focus
Change(View v, boolean has
Focus
) {
if (has
Focus
) {
// 处理获取焦点事件
} else {
// 处理失去焦点事件
4. 通过键盘事件处理焦点:可以在处理键盘事件时,根据当前焦点 View 的 ID 或位置,计算出下一个需要获得焦点的 View,并
调用
其
request
Focus
() 方法来设置焦点,例如:
editText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) {
View nextView = v.
focus
Search(View.
FOCUS
_DOWN);
if (nextView != null) {
nextView.
request
Focus
();
return true;
return false;
以上是几种常见的焦点移动方式,可以根据自己的需求选择合适的方式来实现。