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
ViewRoot中的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);
方法requestFocus()代码如下:
public final boolean requestFocus() {
return requestFocus(View.FOCUS_DOWN);
public final boolean requestFocus(int direction) {
return requestFocus(direction, null);
public boolean reque
相信很多刚接触AndroidTV开发的开发者,都会被各种焦点问题给折磨的不行。不管是学技术还是学习其他知识,都要学习和理解其中原理,碰到问题我们才能得心应手。下面就来探一探Android的焦点分发的过程。
Android焦点分发过程
Android焦点事件的分发是从ViewRootImpl的processKeyEvent开始的,源码如下: private int processK
在NumberPicker被按下的时候,会调用hideSoftInput(),里面改变了mInputText的visibility值,变为了INVISIBLE,但是requestFocus()需要VISIBLE,所以,我们观察到,当NumberPicker被滑动后,就无法被requestFoucs()再聚焦了,就是这个原因。
1.连接WindowManager和DecorView的纽带2.完成view的measure,layout,draw3.向DecorView分发按键、触摸事件等。关于按键事件和焦点寻找:先判断是否有按键事件处理1.若返回true,则打断该方向上的焦点寻找。2.若返回fasle,则根据指定的方向寻找最近且可获取焦点的view2.1判断view的类型,是否为ViewGroup。
和 invalidateO的调用有点相似,requestFocusO也是不能独自完成的,当一个视图想要获取焦点时,
必须请求它的父视图完成该操作,为什么呢?因为父视图知道当前哪个视图正在拥有焦点,如果要进行
焦点切换,则必须先告诉原先的视图放弃焦点,而这些操作所需要的信息是在父视图中保存的,所以
requestFocus()也必须由父视图完成。
该函数有如下三个不同的版本。
• requestFocusO:无参数,它被转换成 requestFocus(View.FOCUS__DOWN)。
• request
首先会更新当前 View 的标记位 mPrivateFlags 记录自己的 isFocused 状态,PFLAG_FOCUSED表示当前View获取焦点,接着通过 rootView 查找到当前的焦点赋值给 oldFocus,以用于后续逐层清理旧的焦点View的焦点,然后调用 parent 的 requestChildFocus 方法告知 parent 自己当前获取到焦点。View的实现比较简单,就是查询一下自己的mPrivateFlags标记位,如果获取到了焦点就将自己返回,否则返回null。
这篇文章使用一个demo来描述一下android焦点分发的基本流程,描述一下我们一个控件请求焦点到我们切换焦点的时候走的是怎么样一个流程,要是对android的焦点的基础不了解的请看我前面的文章:Android焦点分发基础 ,先对android焦点有一个感性得认识。
首先我需要先自定义FocusButton、FocusLinearLayout和FocusRelativeLayout三个控件
前言相信很多刚接触AndroidTV开发的开发者,都会被各种焦点问题给折磨的不行。不管是学技术还是学习其他知识,都要学习和理解其中原理,碰到问题我们才能得心应手。下面就来探一探Android的焦点分发的过程。Android焦点分发,拦截过程的实现Android焦点事件的分发是从ViewRootImpl的processKeyEvent开始的,源码如下:private int processKeyEv...