TV开发焦点跑飞的问题

在使用TV开发时,有可以提供使用的leanback类库里的VerticalGridView等代替手机上的RecyclerView,但实际开发中,经常还是要用到RecyclerView,RecyclerView虽然强大,在TV上却经常遇到焦点跑飞的情况,原因:
RecyclerView在长按遥控器的情况下会导致Item的焦点丢失或者说是飞到别的控件上。主要是因为RecyclerView设置适配器,将数据全部填充进去之后,并不会将所有的item的view创建出来,只会创建出显示和需要的item的View,没有显示的Item的View(nextFocusView)很可能没有被创建。所以在快速移动的时候,RecyclerView并没有创建那个应该获取焦点的View,所以导致焦点飞到其他可承载焦点的View上去了。网上的一些解决思路:
方案一(仍有小概率跑飞,且出现焦点换列概率较高):

public class FocusedLayoutManager extends GridLayoutManager {
    public FocusedLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
    }

    public View onInterceptFocusSearch(View focused, int direction) {

        int currentPosition = getPosition(getFocusedChild());//这里要用这个方法
        int count = getItemCount();
        int lastVisiblePosition = findLastVisibleItemPosition();
        switch (direction) {
            case View.FOCUS_RIGHT:
                currentPosition++;
                break;
            case View.FOCUS_LEFT:
                currentPosition--;
                break;
        }
        if (currentPosition < 0 || currentPosition > count) {
            return focused;
        } else {
            if (currentPosition > lastVisiblePosition) {
                scrollToPosition(currentPosition);
            }
        }
        return super.onInterceptFocusSearch(focused, direction);
    }
}

方案二(效果同方案一,且由于限制了速度,固不能快速向下):

private long mLastKeyDownTime;
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        long current = System.currentTimeMillis();
        boolean dispatch;
        if (current - mLastKeyDownTime < 150) {
            dispatch= true;
        } else {
            dispatch= super.onKeyDown(keyCode, event);
            mLastKeyDownTime = current;
        }
        return dispatch;
    }

自己探索:既然还没创建出来,那就让RecyclerView scroll一段距离把它显示出来呗:

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        // 解决焦点跑飞
        View focusedView = rv_main.findFocus();
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
                // 向下按
                View nextView = FocusFinder.getInstance().findNextFocus(rv_main, focusedView, View.FOCUS_DOWN);
                if (nextView != null) {
                    int[] location = new int[]{0, 0};
                    nextView.getLocationInWindow(location);
                    // mScrollLevel可能分横竖屏有两个值
                    if (location[1] > mScrollLevel) {
                        rv_main.smoothScrollBy(0, mItemHeight);
                    }
                    nextView.requestFocus();
                } else {
                    rv_main.smoothScrollBy(0, mItemHeight);
                }
                return true;
            }
        } else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
            // 向上按
            int[] location = new int[]{0, 0};
            focusedView.getLocationOnScreen(location);
            if (location[1] < mItemHeight) {
                rv_main.smoothScrollBy(0, -mItemHeight);
                return true;
            }
        }

        return super.dispatchKeyEvent(event);
    }

另一个思路:使用leanback的VerticalGridView,取其内部实现的RecyclerView来设置数据。

你可能感兴趣的:(Android)