zoukankan      html  css  js  c++  java
  • 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 project师的 bug,快到 google groups 提问 ^-^!

    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。

  • 相关阅读:
    delphi7在windows server 2003企业版上不能打开项目的选项(Options)窗口的解决方法
    简单的两个字“谢谢”,会让我坚持我的写作,我也要谢谢你们
    F41GUT 安装Windows server 2003系统后无法安装显卡驱动的解决办法
    远程桌面无法登录windows server 2003服务器
    F41GUT 安装Windows server 2003系统后无法安装显卡驱动的解决办法
    MS SQL Server 2000版在windows server 2003企业版系统上运行时造成数据库suspect的解决方法
    delphi7在windows server 2003企业版上不能打开项目的选项(Options)窗口的解决方法
    远程桌面无法登录windows server 2003服务器
    MS SQL Server 2000版在windows server 2003企业版系统上运行时造成数据库suspect的解决方法
    关于ajax 和josn
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/7018225.html
Copyright © 2011-2022 走看看