RecyclerView在TV使用中碰到的问题和解决方案

一、判断recyclerview是否滑到最后一行

在使用种如果界面上要显示一个标识,来告知用户已经滑到了最后一行,那么可以通过推recyclerview的滑动监听,来进行设置:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dy == 0) {
                    initMoreVisibility();
                }
                if (mLayoutManager != null) {
                    int totalItemCount = mLayoutManager.getItemCount();
                    int lastVisibleItem = mLayoutManager.findLastCompletelyVisibleItemPosition();
                    if (dy > 0) {
                        int visibleThreshold = 1;
                        if (totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                            more.setVisibility(View.INVISIBLE);
                        } else {
                            more.setVisibility(View.VISIBLE);
                        }
                    } else if (dy < 0) {
                        int visibleThreshold = 0;
                        if (totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                            more.setVisibility(View.INVISIBLE);
                        } else {
                            more.setVisibility(View.VISIBLE);
                        }
                    }
                }
            }
        });

二、在TV中使用recyclerview,快速按遥控(长按),焦点跑飞的的问题

在长按或者快速按遥控器是,recyclerview的焦点跑飞。主要原因是在滑动的过程中,下一个要获取焦点的view,还处于绘制渲染阶段(PFLAG_INVALIDATED,PFLAG_DIRTY_MASK),这个阶段的view是无法获取焦点的,所以可以通过重写recyclerview中的dispatchKeyEvent ,在这边进行对按键进行过滤,取消一些view还处于不能获取焦点的按键事件。(在这边也一并进行了边界的判断

 protected boolean isBorder(KeyEvent event) {
        int focusDirection = event.getKeyCode();
        View view = this.getFocusedChild();
        LayoutManager layoutManager = this.getLayoutManager();
        int focusPos = layoutManager.getPosition(view);
        if (layoutManager instanceof GridLayoutManager) {
            GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
            int spanCount = gridLayoutManager.getSpanCount();
            int itemCount = layoutManager.getItemCount();
            int rowCount;
            int row;
            int span;
            if (isHeader && itemCount != 1) {
                rowCount = (int) (Math.ceil((double) (itemCount - 1) / spanCount) + 1);
                if (focusPos != 0) {
                    row = (focusPos - 1) / spanCount + 2;
                } else {
                    row = (focusPos - 1) / spanCount + 1;
                }
                span = (focusPos - 1) % spanCount + 1;
            } else {
                rowCount = (int) Math.ceil((double) itemCount / spanCount);
                row = focusPos / spanCount + 1;
                span = focusPos % spanCount + 1;
            }
            if (event.hasNoModifiers()) {
                switch (focusDirection) {
                    case KeyEvent.KEYCODE_DPAD_DOWN:
                        if (row == rowCount) {
                            return borderListener.onKeyBottomDown();
                        } else {
                            //处理长按焦点错误问题;
                            View nextView = view.focusSearch(View.FOCUS_DOWN);
                            if (nextView != null) {
                                //过虑还没绘制完成的view和正在修改的view
                                if (!nextView.willNotDraw() || nextView.isDirty()) {
                                    return true;
                                }
                                // 这个根据布局的需求进行调整,用于解决长按遥控器,焦点跑掉的问题
                                if (nextView.getTop() > ScreenUtil.dip2px(getContext(), 680)) {
                                    return true;
                                }
                            }
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_UP:
                        if (row == 1) {
                            return borderListener.onKeyTopUp();
                        } else if (row == 2 && headerIsNull) {
                            return borderListener.onKeyTopUp();
                        } else {
                            //处理长按焦点错误问题
                            View nextView = view.focusSearch(View.FOCUS_UP);
                            if (nextView != null) {
                                if (!nextView.willNotDraw()) {
                                    return true;
                                }
                            }
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        if (span == spanCount) {
                            return borderListener.onKeyRightEnd();
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        if (span == 1) {
                            return borderListener.onKeyLeftEnd();
                        }
                        break;
                }
            }
        }

        return super.dispatchKeyEvent(event);
    }

三、当界面使用activity + fragment+viewpager 多个界面切换时,焦点的处理

recyclerview在这种情况时,界面切换获取的焦点是recyclerview缓存中的最后一个view,而一般我们希望的是最靠近左边或右边的View.
左边滑到recyclerview:

int childCount = mRecyclerView.getChildCount();
        int row = (int) (Math.ceil((double) (childCount - 1) / mLayoutManager.getSpanCount()) + 1);
        int position = mRecyclerView.getChildViewHolder(mRecyclerView.getChildAt(0)).getLayoutPosition();
        int cvPosition = mLayoutManager.findLastCompletelyVisibleItemPosition();
        int vPosition = mLayoutManager.findLastVisibleItemPosition();
        int effect = (cvPosition == vPosition ? 0 : 1);
        row = row - effect;
        if (mRecyclerView.isHeaderIsNull()) {
            int focusPosition;
            if (row <= 2) {
                focusPosition = 0;
            } else {
                int effect2 = position == 0 ? 1 : 2;
                focusPosition = effect2 * mLayoutManager.getSpanCount();
            }
            if (position == 0) {
                mRecyclerView.getChildAt(1).requestFocus();
            } else {
                mRecyclerView.getChildAt(focusPosition - 6).requestFocus();
            }

        } else {
            if (row <= 2) {
                header.positionRequestFocus(0);
            } else {
                int effect2 = position == 0 ? 1 : 2;
                int focusPosition = effect2 * mLayoutManager.getSpanCount();
                if (position == 0) {
                    mRecyclerView.getChildAt(1).requestFocus();
                } else {
                    mRecyclerView.getChildAt(focusPosition - 6).requestFocus();
                }
            }
        }

右边滑到recyclerview

int childCount = mRecyclerView.getChildCount();
        int row = (int) (Math.ceil((double) (childCount - 1) / mLayoutManager.getSpanCount()) + 1);
        int position = mRecyclerView.getChildViewHolder(mRecyclerView.getChildAt(0)).getLayoutPosition();
        int cvPosition = mLayoutManager.findLastCompletelyVisibleItemPosition();
        int vPosition = mLayoutManager.findLastVisibleItemPosition();
        int effect = (cvPosition == vPosition ? 0 : 1);
        row = row - effect;
        if (mRecyclerView.isHeaderIsNull()) {
            int focusPosition;
            if (row <= 2) {
                focusPosition = childCount <= 7 ? (childCount - 1) : 6;
            } else {
                int effect2 = position == 0 ? 1 : 2;
                focusPosition = effect2 * mLayoutManager.getSpanCount();
            }
            if (position == 0) {
                mRecyclerView.getChildAt(focusPosition).requestFocus();
            } else {
                mRecyclerView.getChildAt(focusPosition - 1).requestFocus();
            }

        } else {
            if (row <= 2) {
                header.positionRequestFocus(5);
            } else {
                int effect2 = position == 0 ? 1 : 2;
                int focusPosition = effect2 * mLayoutManager.getSpanCount();
                if (position == 0) {
                    mRecyclerView.getChildAt(focusPosition).requestFocus();
                } else {
                    mRecyclerView.getChildAt(focusPosition - 1).requestFocus();
                }
            }
        }

控制recyclerview滑动的距离
有时候需要在recyclerview中添加不需要获取焦点的view用于对内容的说明,那么就需要在滑动的过程中多滑动一些,把这个描述内容和显示内容一起显示在屏幕中,可以通过重写Manager中的scrollVerticallyBy或者scrollHorizontallyBy (根据滑动方向):

 @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        double speedRatio;
        if (dy > 0) {
            speedRatio = speedDownRatio;
        } else {
            speedRatio = speedUpRatio;
        }
        int a = super.scrollVerticallyBy((int) (speedRatio * dy), recycler, state);
        if (a == (int) (speedRatio * dy)) {
            return dy;
        }
        return a;

    }

这边附上一个demo,上面有使用中的效果图

RecyclerViewTvdemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值