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。

  • 相关阅读:
    网友谈:Dictionary.ContainsKey和List.BinarySearch哪个效率高
    C# WinForm 中在窗口标题栏上加按钮
    将Txt文件转换成dataset[原创]
    四个常见的排序算法[原创]
    改版后的groupbox[原创]
    转 五种提高 SQL 性能的方法
    转 牢记!SQL Server数据库开发的二十一条军规(SQL收藏)
    源码详解Java的反射机制
    java多线程采集+线程同步
    jQgrid API
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/7018225.html
Copyright © 2011-2022 走看看