这篇文章使用一个demo来描述一下android焦点分发的基本流程,描述一下我们一个控件请求焦点到我们切换焦点的时候走的是怎么样一个流程,要是对android的焦点的基础不了解的请看我前面的文章:Android焦点分发基础 ,先对android焦点有一个感性得认识。
首先我需要先自定义FocusButton、FocusLinearLayout和FocusRelativeLayout三个控件,主要就是重写里面的findFocus、requestFocus、requestChildFocus和focusSearch这几个方法,当然Button是没有requestChildFocus这个方法的。下面给出FocusLinearLayout的代码,其余两个跟这个一样的,最后会给出demo代码的。
package view.danxx.com.focustest;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
/**
* Created by Danxingxi on 2016/4/3.
*/
public class FocusLinearLayout extends LinearLayout {
private final static String TAG = "danxx";
private final static String LogTag = "FLL-->";
public FocusLinearLayout(Context context) {
super(context);
}
public FocusLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FocusLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public View findFocus() {
Log.d(TAG , LogTag+"findFocus");
return super.findFocus();
}
@Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
Log.d(TAG , LogTag+"requestFocus");
return super.requestFocus(direction, previouslyFocusedRect);
}
@Override
public void requestChildFocus(View child, View focused) {
super.requestChildFocus(child, focused);
Log.d(TAG, LogTag + "requestChildFocus");
}
@Override
public View focusSearch(View focused, int direction) {
Log.d(TAG, LogTag + "focusSearch");
return super.focusSearch(focused, direction);
}
}
下面一张图描述了布局关系:
我们在MainActivity中直接把FocusButton1请求焦点
接下来看看打印出来的日志信息:
Log TAG对应关系:
TBtn :FocusButton
FRL: FocusRelativeLayout
FLL: FocusLinearLayout
可以看到,焦点请求(requestFocus)是从父容器向下寻找的,焦点的寻找(findFocus)也是从父容器向下寻找。
上面是我们使FocusButton1主动请求获取焦点,下面我们试试不主动获取焦点会怎么样:
其实还是FocusButton1获得了焦点,只是FocusButton1获得焦点是系统自己执行的,系统自动请求焦点也是从最顶层的容器控件开始向内请求的,我们进入一个界面系统会自动请求焦点,寻找焦点,最后使用一个控件获得焦点。
我们再尝试一下切换焦点,看看focusSearch是怎么工作的,我们把焦点向下按到第二个按钮。
看看Log信息:
我们可以看到,切换焦点的时候,也是要从最顶层的父容器寻找到焦点(findFocus),然后从获得到焦点的控件开始从内向外调用focusSearch寻找下一个焦点控件。
总结:Android的焦点分发跟事件分发类似,有一个从内向外,从外向内的过程,焦点分发中,寻找当前的焦点控件(findFocus)和焦点的请求(requestChildFocus)都是从外向内的,就是从顶层的父容向内层的子容器寻找和请求,但是搜寻下一个焦点(focusSearch)是从当前焦点控件开始的,就是从内向外寻找,到这里我们知道了Android焦点分发的一个基本流程,但是还不知道焦点分发的原理,后面我会写一篇《Android焦点分发原理》来分析为啥是这样的一个流程。下一篇文章会介绍 findFocus、requestFocus、requestChildFocus和focusSearch这几个方法。
思考:既然焦点分发是层层传递的,我就可以拦截焦点分发,可以代替系统来自定义我们的焦点跳转,自定义一个容器layout,写上两个接口,在重写的focusSearch方法中调用对应的接口方法,这样我就可以操控焦点 分发,其实系统提供了setNextFocusDownId类似的方法,可以简单地控制焦点,但是这样不是很灵活。