View 和 ViewGroup 的 hasFocusable

在 android 中,焦点的获取和事件差不多,有一个分发机制,一般来说View 树上上层节点的 ViewGroup 比底层节点的 View 有更高的优先级获取焦点,这体现在 ViewGroup 有一个属性 descendantFocusability 可以用来控制焦点获取的优先级。 该属性的值有三种:

  • beforeDescendants:ViewGroup 会优先其子类控件而获取到焦点,如果父控件不获取焦点,子控件才可能会获得焦点
  • afterDescendants:只有当其子类控件不需要获取焦点时,ViewGroup 才可能获取焦点
  • blocksDescendants:viewgroup 会阻塞子类控件获得焦点,无论 ViewGroup 是否获取焦点,子控件都不能够获得焦点

如何判断 View 是否能够获取焦点

因为上面的原因,判断一个 View 是否有可能获得焦点,就与它所有的父节点有关系了,所以 View 的 hasFocusable 方法实现如下:

public boolean hasFocusable() {
    if (!isFocusableInTouchMode()) {
        for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) {
            final ViewGroup g = (ViewGroup) p;
            if (g.shouldBlockFocusForTouchscreen()) {
                return false;
            }
        }
    }
    return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable();
}
  1. 在触摸模式下如果不可获取焦点的情况,先遍历 View 的所有父节点,如果有一个父节点设置了阻塞子 View 获取焦点,那么该 View 就不可能获取焦点
  2. 在触摸模式下如果不可获取焦点的情况,并且没有父节点设置阻塞子 View 获取焦点,和在触摸模式下如果可以获取焦点,那么才判断 View 自身的 visiable 和 focusable 属性,来决定是否可以获取焦点,不可见的 View 当然也不能获取焦点,所以只有 visiable 和 focusable 同时为 true,该View 才可能获取焦点

判断 ViewGroup 是否能够获取焦点

判断一个 ViewGroup 是否可能获取到焦点,也与它的子 View 有关系了,如果子 View 可以获取焦点,辣么,就可以算作这个 ViewGroup 也可能获取(消耗)焦点,所以 ViewGroup 的 hasFocusable 方法实现如下:

public boolean hasFocusable() {
   if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
        return false;
    }

    if (isFocusable()) {
        return true;
    }

    final int descendantFocusability = getDescendantFocusability();
    if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
        final int count = mChildrenCount;
        final View[] children = mChildren;

        for (int i = 0; i < count; i++) {
            final View child = children[i];
            if (child.hasFocusable()) {
                return true;
            }
        }
    }

    return false;
}

根据上面的源码可知,判断 ViewGroup 是否能够获取焦点就简单多了

  1. 如果 ViewGroup visiable 和 focusable 都为 true,就算能够获取焦点
  2. 如果不满足第 1 点,就算子 View 节点能够获取焦点,该 ViewGroup 也算能获取焦点
  3. 否则,就算作不能够获取到焦点
  4. ViewGroup 自己能够获取焦点,完全没有考虑是否在触摸模式的情况,不晓得是不是 google 工程师的 bug

View 是否能够获取焦点的实际应用

View 是否能够获取焦点,通常在 AbsListView 的 OnItemClickListener,EditText,Button 的使用和 key 事件分发中会应用到。比如 ListView 的 OnItemClickListener,只有在 ListView 的 ItemView 不能获取到 focus 的情况下,才会调用 OnItemClickListener 的 onItemClick 方法。具体代码可以参考 AbsListView 的 onTouchUp 方法:

private void onTouchUp(MotionEvent ev) {
    switch (mTouchMode) {
    case TOUCH_MODE_DOWN:
    case TOUCH_MODE_TAP:
    case TOUCH_MODE_DONE_WAITING:
       ......
       该省就省,我是省略代码分割符 ^_^
       ......
            if (inList && !child.hasFocusable()) {
                if (mPerformClick == null) {
                    mPerformClick = new PerformClick();
                }

                final AbsListView.PerformClick performClick = mPerformClick;
                performClick.mClickMotionPosition = motionPosition;
                performClick.rememberWindowAttachCount();

                 ......
                 该省就省,我是省略代码分割符 ^_^
                 ......
                        mTouchModeReset = new Runnable() {
                            @Override
                            public void run() {
                                mTouchModeReset = null;
                                mTouchMode = TOUCH_MODE_REST;
                                child.setPressed(false);
                                setPressed(false);
                                if (!mDataChanged && !mIsDetaching && isAttachedToWindow()) {
                                    performClick.run();
                                }
                            }
                        };
                        postDelayed(mTouchModeReset,
                                ViewConfiguration.getPressedStateDuration());
                    } else {
                        mTouchMode = TOUCH_MODE_REST;
                        updateSelectorState();
                    }
                    return;
                } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
                    performClick.run();
                }
            }
        }
         ......
         该省就省,我是省略代码分割符 ^_^
         ......
}

从上面代码的第 9 行可知,ListView 的 ItemView 的 hasFocusable 方法必须返回 fasle,才会执行 performClick.run(),才会执行到 OnItemClickListener 的 onItemClick 方法。这也就是为什么通常我们在使用 ListView 的 OnItemClickListener 方法的时候要把 Item 布局文件的根节点的 descendantFocusability 属性设置为 blocksDescendants,并且不能该节点的 focusable 属性为 true。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-07 11:26:53

View 和 ViewGroup 的 hasFocusable的相关文章

Android基础入门教程——2.1 View与ViewGroup的概念

Android基础入门教程--2.1 View与ViewGroup的概念 标签(空格分隔): Android基础入门教程 本节引言: 告别了第一章,迎来第二章--Android中的UI(User Interface)组件的详解, 而本节我们要学习的是所有控件的父类View和ViewGroup类!突发奇想,直接翻译官方文档对 这两个东西的介绍吧,对了,天朝原因,google上不去,Android developer上不去,我们可以 改hosts或者用vpn代理,当然也可以像笔者一样使用国内的API

Android的View和ViewGroup分析

1. 概念 Android中的View与我们以前理解的"视图"不同.在Android中,View比视图具有更广的含义,它包含了用户交互和显示,更像Windows操作系统中的window. ViewGroup是View的子类,所以它也具有View的特性,但它主要用来充当View的容器,将其中的View视作自己的孩子,对它的子View进行管理,当然它的孩子也可以是ViewGroup类型. ViewGroup(树根)和它的孩子们(View和ViewGroup)以树形结构形成了一个层次结构,V

[Android] View和ViewGroup事件分发机制

在android开发中会经常遇到滑动冲突(比如ScrollView或是SliddingMenu与ListView的嵌套)的问题,需要我们深入的了解android事件响应机制才能解决,事件响应机制已经是android开发者必不可少的知识. 1.涉及到事件响应的常用方法构成 用户在手指与屏幕接触过程中通过MotionEvent对象产生一系列事件,它有四种状态: MotionEvent.ACTION_DOWN :手指按下屏幕的瞬间(一切事件的开始) MotionEvent.ACTION_MOVE :手

View与ViewGroup有什么区别?

百度知道:http://zhidao.baidu.com/link?url=B5MFOzDlww8soYqr5CL5FldH4sXD6eumS1XTRn8XEh8gu4mKjQdPkJSLIBt7u_xtf7jcrJRJEGWIQcWEq1Z-nq Android的UI界面都是由View和ViewGroup及其派生类组合而成的. 其中,View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的. View对象是Android平台中用户界面体现的基础单

Android View系统分析之二View与ViewGroup

目录 在Android View系统分析之从setContentView说开来(一)一文中,我们从setContentView开始阐述了Android中的视图层次,从设置内容布局到整个视图层次的建立的过程.并且对View和ViewGroup的关系进行了简单的介绍,今天我们继续来深入的了解Android中的View和ViewGroup. ViewGroup与View的关系 我们在定义一个布局时,在它的顶层通常都是使用LinearLayout或者RelativeLayout等组件来包装一些子控件,例

Android View和ViewGroup

View和ViewGroup Android的UI界面都是由View和ViewGroup及其派生类组合而成的. 其中,View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的. View对象是Android平台中用户界面体现的基础单位. View类是它称为“widgets(工具)”的子类的基础,它们提供了诸如文本输入框和按钮之类的UI对象的完整实现. ViewGroup类同样为其被称为“Layouts(布局)”的子类奠定了基础,它们提供了象流式布局

Android——View、ViewGroup事件(Touch事件)处理机制总结

Android中的事件 Touch事件,四种状态: ACTION_DOWN     -->   表示按下了屏幕,一个事件必然从ACTION_DOWN开始 ACTION_MOVE      -->   表示移动手势 ACTION_UP            -->  表示离开屏幕 ACTION_CANCEL  -->   表示取消手势,一般由程序产生,不会由用户产生 一个ACTION_DOWN, n个ACTION_MOVE,1个ACTION_UP,就构成了Android中众多的事件.

Android视图控件架构分析之View、ViewGroup

在Android中,视图控件大致被分为两类,即ViewGroup和View,ViewGroup控件作为父控件,包含并管理着子View,通过ViewGroup和View便形成了控件树,各个ViewGoup对象和View对象就是控件树中的节点.在控件树中,以树的深度来遍历查找对应的控件元素,同时,上层控件负责子控件的测量与绘制,并传递交互事件. Android控件树: AndroidUI界面架构图: 一.测量View的工具类:MeasureSpec 1.MeasureSpec包含了测量的模式和测量的

android view、viewgroup 事件响应拦截处理机制

文章中会用到部分网络资源,首先将原作者的链接附上. 但是还是会附上数量较大的关于此部分内容的自己的思考. ------------------------------------------------------------------------------------write by mcdullsin 将原作者的链接附上可以为搜索引擎评价原始作者的文章提供自己能力所及的帮助,也算是对分享自己技术的各位前辈的一种感激吧. 1.android编程下touch事件的分发和消费机制 2.andr