禁用对片段的关注

Disable focus on fragment

我正在做TV平台的应用,使用RCU做导航

我有一个用例,我有两个片段,一个在另一个片段之上,同时在屏幕上可见。

有没有办法禁用下面的聚焦片段? 片段视图上的 setFocusable(false) 不起作用,我能够聚焦下面片段中的元素。

提前致谢。

最后我想到的解决办法是:

为片段添加了自定义生命周期侦听器,即:onFragmentResumeonFragmentPause 事件,我当我需要 show/hide 或在片段之间切换时手动调用。

@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);
    }
}

我解决了这个问题,为片段布局的父 ViewGroup 创建自定义 class。在您的自定义 ViewGroup 中,您可以覆盖方法

focusSearch(focused: View?, direction: Int)

添加此逻辑:

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
}

当新的焦点视图不属于此 parent 时比 return null。当无法访问其他一些视图焦点时,我会在 when 个案例中手动管理它。

我遇到了同样的问题,接受的答案对我有用。

这是我目前的实现版本(可以改进):

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

}