Android TV横向滚动实现Launcher的RecyclerView第二弹

上一篇:Android TV横向滚动网格布局——RecyclerView的使用
上一篇粗略的讲了一下RecyclerView,这一篇主要是就横向滚动的做一下补充 Demo下载

关于RecyclerView 的焦点获取以及其他问题补充记录:

1.RecyclerView没有提供类似与OnItemClickListener、OnItemLongClickListener、OnItemSecletListener等等之类的监听器。所以需要在Adapter上设置监听器。具体代码在上一篇

2.关于使用遥控器操作,焦点的获取。遥控器的上、下、左、右按键是有系统底层接收并处理的。除非有特定需要一般的焦点变化是无需手动处理的。

*如果有特定需要,比如焦点在RecyclerView的某个Item上时,按下了OK键,需要跳转到一个新的界面(Activity),此时应该设置监听。

// 1.监听也是设置在Adapter中
public class SimpleRecyclerAdapter extends RecyclerView.Adapter<SimpleRecyclerAdapter.ViewHolder>{
    ...
    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        ...
        holder.itemView.setOnKeyListenernew View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KEYCODE_DPAD_CENTER) {
                    // TODO 具体业务逻辑,比如页面跳转
                }
                return false;
            }
        });
    }
}

3.开发中的问题总结。通常情况,遥控器的上下左右按键的监听系统都处理好了,但是有时候按键处理会出现一下问题:
这里写图片描述

比如,焦点现在在最后一列的某个Item上,但这个Item后面还有很多列,只是此时屏幕上没显示出来,需要向左滚动,才能看到后面的Item,但是此时系统的监听不会自己滚动,并且按下遥控右键不会有反应。此时就需要我们想办法解决一下。

我的思路是这样:
1.由于系统的遥控器方向键监听是需要在当前屏幕上知晓是否后面还有Item才可以继续按右键的。所以设计一个算法在RecyclerView中,使得焦点到达最右边时,父控件向左边滚出一定距离;而焦点到达最左边时,父控件向右边滚动一定距离。
2.此时再按下方向键,系统又可以使得下一个Item获得焦点了。

    /**
     * 将指定item平滑移动到整个view的中间位置
     * @param position 指定的item的位置
     */
    public void smoothHorizontalScrollToNext(int position) {
        Log.d(TAG, "position=" + position);
        StaggeredGridLayoutManager manager = (StaggeredGridLayoutManager) getLayoutManager();
        int[] startItems = manager.findFirstVisibleItemPositions(null);
        int[] endItems = manager.findLastVisibleItemPositions(null);
        if (position == 0) {
            int parentWidth = getWidth();
            View firstView = getChildAt(0);
            mLastX = 1174;
            mScroller.startScroll(mLastX, 0, -500, 0);
            postInvalidate();

            childWidth = firstView.getWidth();
            int preLastPos = endItems[0] - 1;
            View specialView = getChildAt(preLastPos);
            if (specialView == null) return;
            specialLeft = specialView.getLeft();
            specialRight = parentWidth - specialLeft;
            Log.d(TAG, "一屏的倒数第二行位置是:" + preLastPos + ", 父容器宽度:" + parentWidth
                    + ", 超出位置(极右位置):" + specialLeft + ", 不达位置(极左位置):" + specialRight);
        }

        int targetPos = position - startItems[0];
        View targetView = getChildAt(targetPos);
        if (targetView == null) {
            Log.i(TAG, "TargetView is null!");
            return;
        }
        int targetLeft = targetView.getLeft();
        int targetRight = targetView.getRight();

        Log.d(TAG, "目标位置:" + targetPos + ", 目标左位置:" + targetLeft  + ", 目标右位置:" + targetRight);

        if (targetLeft > specialLeft) {
            // 获得焦点的不全显示item将自动全显示。
            // 因此,到达极右位置只需移动下一个不全显示的偏置距离
            mLastX = targetLeft;
            mScroller.startScroll(targetLeft, 0, -childWidth/2 , 0);
            postInvalidate();
            Log.d(TAG, "<----");
        } else if (targetRight < specialRight) {
            // 到达极左位置
            mLastX = targetRight;
            mScroller.startScroll(targetRight, 0, childWidth/2, 0);
            postInvalidate();
            Log.d(TAG, "---->");
        }
    }

    public void smoothVerticalScrollToNext(int position) {
        Log.d(TAG, "position=" + position);
        GridLayoutManager manager = (GridLayoutManager) getLayoutManager();
        int startItems = manager.findFirstVisibleItemPosition();
        int endItems = manager.findLastVisibleItemPosition();
        if (position == 0) {
            int parentWidth = getWidth();
            View firstView = getChildAt(0);
            mLastX = 1174;
            mScroller.startScroll(mLastX, 0, -500, 0);
            postInvalidate();

            childWidth = firstView.getWidth();
            int preLastPos = endItems[0] - 1;
            View specialView = getChildAt(preLastPos);
            if (specialView == null) return;
            specialLeft = specialView.getLeft();
            specialRight = parentWidth - specialLeft;
            Log.d(TAG, "一屏的倒数第二行位置是:" + preLastPos + ", 父容器宽度:" + parentWidth
                    + ", 超出位置(极右位置):" + specialLeft + ", 不达位置(极左位置):" + specialRight);
        }

        int targetPos = position - startItems[0];
        View targetView = getChildAt(targetPos);
        if (targetView == null) {
            Log.i(TAG, "TargetView is null!");
            return;
        }
        int targetLeft = targetView.getLeft();
        int targetRight = targetView.getRight();

        Log.d(TAG, "目标位置:" + targetPos + ", 目标左位置:" + targetLeft  + ", 目标右位置:" + targetRight);

        if (targetLeft > specialLeft) {
            // 获得焦点的不全显示item将自动全显示。
            // 因此,到达极右位置只需移动下一个不全显示的偏置距离
            mLastX = targetLeft;
            mScroller.startScroll(targetLeft, 0, -childWidth/2 , 0);
            postInvalidate();
            Log.d(TAG, "<----");
        } else if (targetRight < specialRight) {
            // 到达极左位置
            mLastX = targetRight;
            mScroller.startScroll(targetRight, 0, childWidth/2, 0);
            postInvalidate();
            Log.d(TAG, "---->");
        }
    }

4.更多有关RecyclerView的其他LayoutManager使用方法:
http://blog.csdn.net/lmj623565791/article/details/45059587

—————————不怎么华丽的分割线———————————————

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值