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类似的方法,可以简单地控制焦点,但是这样不是很灵活。
这篇文章使用一个demo来描述一下android焦点分发的基本流程,描述一下我们一个控件请求焦点到我们切换焦点的时候走的是怎么样一个流程,要是对android的焦点的基础不了解的请看我前面的文章:Android焦点分发基础 ,先对android焦点有一个感性得认识。 首先我需要先自定义FocusButton、FocusLinearLayout和FocusRelativeLayout三个控件
事件分发流程相关
一个事件发生后,首先从Acrtivity开始传递,然后一层一层往下传,从上往下调用dispatchTouchEvent方法传递事件:
Activity——>PhoneWindow——>DecorView——>ViewGroup——>…——>View
如果事件传递给最下层的View还没有被消费,就会按照反方向回传给Activity,从下往上调用onTouchEvent方法,最后会到Activity的onTouchEvent()函数,如果Activity也没有消费处理事件,这个事件就会被抛弃:
View——>…——>ViewGroup——>DecorView——>PhoneWin
之前写过一篇Android事件分发机制详解,感觉比较乱,这里再总结一下。网上已经有很多前辈分析过源码,大家可以参考,我这里尽量不做过多的源码分析,仅仅从流程上分析。事件分发和消费我们主要涉及到以下三个方法:dispatchTouchEvent():分发事件onInterceptTouchEvent():拦截事件onTouchEvent():处理事件还需要注意常用的两个接口对以上方法的影响:OnClickListener:点击事件监听OnTouchListener:触摸事件监听最后再认识一下MotionEvent,他表示用户的触摸事件,用户的点击、触摸或者滑动都会产生相应的MotionEvent
在Android开发中,事件分发是比较重要的基础知识,了解并熟悉整套机制有助于更好的分析各种**点击滑动失效问题**,也更有利于去**扩展控件的事件功能**和**开发自定义控件**。
事件分发中**事件指的是一次完整的点击中所包含的事件(如 手指按下屏幕、手指在屏幕中移动、手指抬起等)**;**分发指的是事件从Activity到Window再到ViewGroup最后到View的捕获阶段以及逆方向消费事件的冒泡阶段**。
目前本人在做Android机顶盒开发,在做登录界面的时候发现了一个问题,填写了账号密码后点击登录,正常情况下本应该等待网络服务器的验证然后给出应答,但是在验证过程中点击遥控器的按键,发现停留在登录按钮的焦点会转移~~~
然而这种问题肯定是不允许存在的,在等待验证的过程中用户进行了其他的操做,岂不是打乱或者终端了网络验证过程,然后我把原本可以获取焦点的其他编辑框EditText此时...
04-24 20:07:59.777 1119 2046 D Debug Info: java.lang.Throwable
04-24 20:07:59.777 1119 2046 D Debug Info: at com.android.server.audio.FocusRequester.handleFocusLoss(FocusRequester.java:347)
04-24 20:07:59.777 1119 2046 D Debug Info: at com.an
TouchModeandroid焦点的概念其实一直都在,我们平时做android’开发的时候往往只有EditText有焦点,其他都不需要关心焦点。但是做ott开发,焦点就是经常要考虑的问题。
早期的android不支持触屏,是通过trackball来控制的,后来多了触屏,android 增加了一种概念,叫TouchMode。当用户通过触屏操作手机的时候自动进入叫TouchMode,当用户通过tra