Disable Focus On Fragment
I'm working on application for TV platform and use RCU for navigation. I have use case where I have two fragments one above each other and visible on the screen at the same time. I
Solution 1:
The solution that I've come up with in the end is:
Added custom Lifecycle listeners for the fragment namely: onFragmentResume and onFragmentPause events which I call manually when I need to show/hide or switch between fragments.
@OverridepublicvoidonFragmentResume() {
//Enable focusif (getView() != null) {
//Enable focussetEnableView((ViewGroup) view, true);
//Clear focusable elements
focusableViews.clear();
}
//Restore previous focusif (previousFocus != null) {
previousFocus.requestFocus();
}
}
@OverridepublicvoidonFragmentPause() {
//Disable focus and store previously focusedif (getView() != null) {
//Store last focused element
previousFocus = getView().findFocus();
//Clear current focusgetView().clearFocus();
//Disable focussetEnableView((ViewGroup) view, false);
}
}
/**
* Find focusable elements in view hierarchy
*
* @param viewGroup view
*/privatevoidfindFocusableViews(ViewGroup viewGroup) {
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
View view = viewGroup.getChildAt(i);
if (view.isFocusable()) {
if (!focusableViews.contains(view)) {
focusableViews.add(view);
}
}
if (view instanceofViewGroup) {
findFocusableViews((ViewGroup) view);
}
}
}
/**
* Enable view
*
* @paramviewGroup
* @paramisEnabled
*/privatevoidsetEnableView(ViewGroup viewGroup, boolean isEnabled) {
//Find focusable elementsfindFocusableViews(viewGroup);
for (View view : focusableViews) {
view.setEnabled(isEnabled);
view.setFocusable(isEnabled);
}
}
Solution 2:
I had the same problem and the accepted answer worked for me.
Here is my version of the implementation so far (it can be improved):
abstractclassBaseFragment<....> : Fragment() {
privateval screenFocusHelper = ScreenFocusHelper()
funenableFocus() {
if (view != null) {
// Enable focus
screenFocusHelper.setEnableView(view as ViewGroup, true)
// Clear focusable elements
screenFocusHelper.focusableViews.clear()
}
childFragmentManager.fragments.forEach {
if (it is BaseFragment<*, *>) {
it.enableFocus()
}
}
}
fundisableFocus() {
if (view != null) {
// Store last focused element
screenFocusHelper.previousFocus = view?.findFocus()
// Clear current focus
view!!.clearFocus()
// Disable focus
screenFocusHelper.setEnableView(view as ViewGroup, false)
}
childFragmentManager.fragments.forEach {
if (it is BaseFragment<*, *>) {
it.disableFocus()
}
}
}
}
classScreenFocusHelper{
var previousFocus: View? = nullval focusableViews: MutableList<View> = mutableListOf()
funsetEnableView(viewGroup: ViewGroup, isEnabled: Boolean) {
findFocusableViews(viewGroup)
for (view in focusableViews) {
view.isEnabled = isEnabled
view.isFocusable = isEnabled
}
}
privatefunfindFocusableViews(viewGroup: ViewGroup) {
val childCount = viewGroup.childCount
for (i in0 until childCount) {
val view = viewGroup.getChildAt(i)
if (view.isFocusable) {
if (!focusableViews.contains(view)) {
focusableViews += view
}
}
if (view is ViewGroup) {
findFocusableViews(view)
}
}
}
}
Solution 3:
I solved this making a custom class for the parent ViewGroup
of the fragment layout. In your custom ViewGroup you can override the method
focusSearch(focused: View?, direction: Int)
Adding this logic:
overridefunfocusSearch(focused: View?, direction: Int): View? {
val focusSearch = super.focusSearch(focused, direction)
if (direction == View.FOCUS_DOWN) when (focused?.id) {
R.id.some_view_that_has_focus -> return new_view_focus
}
if (findViewById<View>(focusSearch.id) == null) {//the view found is not part of this parent return nullreturnnull
}
return focusSearch
}
When the new focused view is not part of this parent
than return null. When some other Views focus is not reachable I manage it manually inside when
cases.
Post a Comment for "Disable Focus On Fragment"