Custom Viewgroup Focus Handling
Solution 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:
@OverrideprotectedbooleanonRequestFocusInDescendants(finalint 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.Solution 2:
I have the similar problem. In our android TV application we wanna select the last focused position of our custom menu (it is custom vertical LinearLayout).
Your should override method addFocusables(views: ArrayList<View>, direction: Int, focusableMode: Int)
. This method is called when ViewRootImpl searches all available focusable views. Flags FOCUS_AFTER_DESCENDANTS and FOCUS_BEFORE_DESCENDANTS are only determine position of insertion parent view into focusable views. In case of FOCUS_BEFORE_DESCENDANTS your custom view will be added before your child. In case of FOCUS_AFTER_DESCENDANTS your custom view will be added after your child.
The logic of overriding is to add only your custom view in the list, when your didn't have focused child before.
overridefunaddFocusables(views: ArrayList<View>, direction: Int, focusableMode: Int) {
// if we did have focused child before, we must add only parent view// otherwise our child already has focus, and we don't wont to change focus behaviorif (focusedChild == null) {
views.add(this)
} else {
super.addFocusables(views, direction, focusableMode)
}
}
You also must override requestFocus(direction: Int, previouslyFocusedRect: Rect)
because you mast pass focus into you child or decide that your cannot do it.
overridefunrequestFocus(direction: Int, previouslyFocusedRect: Rect): Boolean =
getViewToFocus()?.requestFocus() ?: false
In this example getViewToFocus() returns the child which I want to be focused or null if we don't have any child
privatefungetViewToFocus() =
when {
lastSelectedPos in0..childCount -> getChildAt(lastSelectedPos)
isNotEmpty() -> getChildAt(0)
else -> null
}
I use Kotlin in examples, but your can use java as well. Enjoy!
Post a Comment for "Custom Viewgroup Focus Handling"