Skip to content Skip to sidebar Skip to footer

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"