Custom ViewGroup focus handling

2019-04-18 23:54发布

问题:

Let's say I have a custom ViewGroup which is focusable and has some child views which are focusable as well (A custom vertical menu for Android set-top-boxes which should react on remote controller).

I need to pass a focus to some of the child views whenever the custom ViewGroup gains the focus.

I set descendantFocusability to beforeDescendants and set OnFocusChangeListener to the custom ViewGroup but OnFocusChangeListener.onFocusChanged()is never called. It looks like beforeDescendants does not work as I expected. Actually setting the beforeDescendants works the same as setting the afterDescendants - The focus is taken by the nearest child view and the custom ViewGroup does not have an opportunity to decide which child view should take the focus.

How can I achieve the desired behavior? What are the best practices to handling focuses in ViewGroups?

回答1:

After digging in Android sources I understand how to dispatch focus to ViewGroup's children. For example I have custom ViewGroup with few EditText fields inside. When the user clicks on ViewGroup (outside of each EditText) I want to dispatch focus to one of fields.

To do this we need to set descendantFocusability to FOCUS_AFTER_DESCENDANTS. It means that we can handle focus event before our custom view will try to focus itself:

setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);


Next step is to override onRequestFocusInDescendants method, it will be invoked before custom view's requestFocus if flag FOCUS_AFTER_DESCENDANTS was set. In this method we can request child focus:

@Override
protected boolean onRequestFocusInDescendants(final int dir, final Rect rect) {
    return getChildAt(this.target).requestFocus();
}

One important thing with this method: if we return true here, our custom view will not be requested to focus (only with FOCUS_AFTER_DESCENDANTS).

In such a manner we can change target field to change which child will be focused when ViewGroup is clicked.


For better understanding you can find requestFocus method in ViewGroup in Android sources.