I was running into this issue as well while coding an application for AndroidTV. It seems that horizontal radio group focus simply does not work with dpad, even when nextFocus{direction} is set on views.
Fortunately, if you are using the leanback library, you can use BrowseFrameLayout.onFocusSearchListener to manage focus yourself by doing the following:
Firstly, make sure your layout and radio group do NOT have focusable or focusableInTouchMode set to true. This will cause the layout/group to receive focus instead of the individual buttons.
Wrap your radio group in a BrowseFrameLayout instead of linear layout:
<android.support.v17.leanback.widget.BrowseFrameLayout
android:id="@+id/browse_frame_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioGroup
android:id="@+id/radio_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/first_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="First Button Text" />
<RadioButton
android:id="@+id/second_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Second Button Text" />
</RadioGroup>
</android.support.v17.leanback.widget.BrowseFrameLayout>
Then in your fragment or activity code, add the following:
BrowseFrameLayout.OnFocusSearchListener onFocusSearchListener =
new BrowseFrameLayout.OnFocusSearchListener() {
@Override
public View onFocusSearch(View focused, int direction) {
if (focused.getId() == R.id.first_button && direction == View.FOCUS_RIGHT) {
return findViewById(R.id.second_button);
} else if (focused.getId() == R.id.second_button && direction == View.FOCUS_LEFT) {
return findViewById(R.id.first_button);
} else if (focused.getId() == R.id.first_button && direction == View.FOCUS_LEFT) {
// return null to allow for default focus transition
return null;
} else {
// return focused to avoid focus change
return focused;
}
}
};
((BrowseFrameLayout) findViewById(R.id.browse_frame_layout)).setOnFocusSearchListener(onFocusSearchListener);
That's it! As mentioned in the comments in the sample snippet, returning null will allow for the system to handle default focus transition, and returning focused will block focus change (helpful for up/down clicks on horizontal radio group for example). Returning any other view will focus that view.
This code can be adjusted for any number/type of views in any direction, so while it can be annoying to implement, it is very useful.
This helped me after a lot of frustration, so I hope it helps you!