Disable focus on fragment

后端 未结 3 1136
小蘑菇
小蘑菇 2021-01-02 19:43

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

相关标签:
3条回答
  • 2021-01-02 19:50

    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:

    override fun focusSearch(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 null
                return null
            }
    
            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.

    0 讨论(0)
  • 2021-01-02 19:58

    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.

    @Override
    public void onFragmentResume() {
    
        //Enable focus
        if (getView() != null) {
    
            //Enable focus
            setEnableView((ViewGroup) view, true);
    
            //Clear focusable elements
            focusableViews.clear();
        }
    
        //Restore previous focus
        if (previousFocus != null) {
            previousFocus.requestFocus();
        }
    }
    
    @Override
    public void onFragmentPause() {
    
        //Disable focus and store previously focused
        if (getView() != null) {
    
            //Store last focused element
            previousFocus = getView().findFocus();
    
            //Clear current focus
            getView().clearFocus();
    
            //Disable focus
            setEnableView((ViewGroup) view, false);
        }
    }
    
    /**
     * Find focusable elements in view hierarchy
     *
     * @param viewGroup view
     */
    private void findFocusableViews(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 instanceof ViewGroup) {
                findFocusableViews((ViewGroup) view);
            }
        }
    }
    
    /**
     * Enable view
     *
     * @param viewGroup
     * @param isEnabled
     */
    private void setEnableView(ViewGroup viewGroup, boolean isEnabled) {
    
        //Find focusable elements
        findFocusableViews(viewGroup);
    
        for (View view : focusableViews) {
            view.setEnabled(isEnabled);
            view.setFocusable(isEnabled);
        }
    }
    
    0 讨论(0)
  • 2021-01-02 20:00

    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):

    abstract class BaseFragment<....> : Fragment() {
    
        private val screenFocusHelper = ScreenFocusHelper()
    
        fun enableFocus() {
            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()
                }
            }
        }
    
        fun disableFocus() {
            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()
                }
            }
        }
    
    }
    
    class ScreenFocusHelper {
    
        var previousFocus: View? = null
    
        val focusableViews: MutableList<View> = mutableListOf()
    
        fun setEnableView(viewGroup: ViewGroup, isEnabled: Boolean) {
            findFocusableViews(viewGroup)
    
            for (view in focusableViews) {
                view.isEnabled = isEnabled
                view.isFocusable = isEnabled
            }
        }
    
        private fun findFocusableViews(viewGroup: ViewGroup) {
            val childCount = viewGroup.childCount
            for (i in 0 until childCount) {
                val view = viewGroup.getChildAt(i)
                if (view.isFocusable) {
                    if (!focusableViews.contains(view)) {
                        focusableViews += view
                    }
                }
                if (view is ViewGroup) {
                    findFocusableViews(view)
                }
            }
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题