安卓机顶盒开发中的焦点之二

一,焦点相关Api说明

  • View中定义了一个方法,用来判断View自身是否获取到焦点或者其内部的子View是否获取到焦点。
/**
 * Returns true if this view has focus itself, or is the ancestor of the
 * view that has focus.
 *
 * @return True if this view has or contains focus, false otherwise.
 */
@ViewDebug.ExportedProperty(category = "focus")
public boolean hasFocus() {
    return (mPrivateFlags & PFLAG_FOCUSED) != 0;
}
  • View中定义了一个isFocused方法,该方法用于判断该View自身是否已经获取到焦点。
/**
 * Returns true if this view has focus
 *
 * @return True if this view has focus, false otherwise.
 */
@ViewDebug.ExportedProperty(category = "focus")
public boolean isFocused() {
    return (mPrivateFlags & PFLAG_FOCUSED) != 0;
}
  • ViewGroup中定义了一个名为setDescendantFocusability的方法,该方法需要指定一个focusability,该值可以为三种类型:
FOCUS_BEFORE_DESCENDANTS:viewgroup会优先其子类控件而获取到焦点
FOCUS_AFTER_DESCENDANTS:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
FOCUS_BLOCK_DESCENDANTS:viewgroup会覆盖子类控件而直接获得焦点

二,界面初始化时系统如何标记初始焦点

  • ViewRootImpl类中有一个比较重要的方法performTraversals,该方法中有如下一段代码:
if (mFirst) {
    // handle first focus request
    if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: mView.hasFocus()="
            + mView.hasFocus());
    if (mView != null) {
        if (!mView.hasFocus()) {
            mView.requestFocus(View.FOCUS_FORWARD);
            if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view="
                    + mView.findFocus());
        } else {
            if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: existing focused view="
                    + mView.findFocus());
        }
    }
}
  • handle first focus request意味着这里处理第一次焦点的请求,注意这里的mView其实就是DecorView,也就是位于view tree的最顶层的View。其本质就是一个FrameLayout,当自身或者其内部子View不包含焦点的时候,就会调用requestFocus尝试标记焦点View。我们再来看下ViewGroup中重写的requestFocus
/**
 * {@inheritDoc}
 *
 * Looks for a view to give focus to respecting the setting specified by
 * {@link #getDescendantFocusability()}.
 *
 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
 * find focus within the children of this group when appropriate.
 *
 * @see #FOCUS_BEFORE_DESCENDANTS
 * @see #FOCUS_AFTER_DESCENDANTS
 * @see #FOCUS_BLOCK_DESCENDANTS
 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
 */
@Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
    if (DBG) {
        System.out.println(this + " ViewGroup.requestFocus direction="
                + direction);
    }
    int descendantFocusability = getDescendantFocusability();

    switch (descendantFocusability) {
        case FOCUS_BLOCK_DESCENDANTS:
            return super.requestFocus(direction, previouslyFocusedRect);
        case FOCUS_BEFORE_DESCENDANTS: {
            final boolean took = super.requestFocus(direction, previouslyFocusedRect);
            return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
        }
        case FOCUS_AFTER_DESCENDANTS: {
            final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
            return took ? took : super.requestFocus(direction, previouslyFocusedRect);
        }
        default:
            throw new IllegalStateException("descendant focusability must be "
                    + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
                    + "but is " + descendantFocusability);
    }
}
  • 我们注意到,这里会根据getDescendantFocusability返回的结果,也就是会先判断我们有没有设置focusability,然后会根据类型首先判断onRequestFocusInDescendants的返回值,如果为真就直接返回了。onRequestFocusInDescendants是个什么鬼呢,接着看:
@SuppressWarnings({"ConstantConditions"})
protected boolean onRequestFocusInDescendants(int direction,
        Rect previouslyFocusedRect) {
    int index;
    int increment;
    int end;
    int count = mChildrenCount;
    if ((direction & FOCUS_FORWARD) != 0) {
        index = 0;
        increment = 1;
        end = count;
    } else {
        index = count - 1;
        increment = -1;
        end = -1;
    }
    final View[] children = mChildren;
    for (int i = index; i != end; i += increment) {
        View child = children[i];
        if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
            if (child.requestFocus(direction, previouslyFocusedRect)) {
                return true;
            }
        }
    }
    return false;
}
  • 我们注意到,其内部遍历所有子View,当子View为可见时,就尝试去标记焦点。因为onRequestFocusInDescendants方法为protected类型,所以我们通常可以重写该方法做一些操作。

你可能感兴趣的:(AndroidTv)