AndroidTV RecyclerView长按焦点乱跳或丢失问题-重写GridLayoutManager

一、问题背景
之前TV端开发遇到的一个问题,RV显示的方式是GridLayoutManager,三列,方向是:VERTICAL,也就是三列显示,上下移动。但是在快速按下键的时候,焦点在最后一排后会跳到旁边的RV上,焦点自动跳走了。要求肯定是移动到最下方的时候,焦点就在最下边呆着,界面如下图:
AndroidTV RecyclerView长按焦点乱跳或丢失问题-重写GridLayoutManager_第1张图片
二、解决方案
参考链接:http://blog.csdn.net/Zou_pl/article/details/77507376
该文重写了LinearLayoutManager,于是仿照人家重写了GridLayoutManager,代码如下:

package com.company.view;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;

public class FocusLayoutManager extends GridLayoutManager {
    public View mSelectedView = null;
    private RecyclerView mRecyclerView;
    public FocusLayoutManager(Context context, int spanCount, int orientation,
                              boolean reverseLayout,RecyclerView recyclerView) {
        super(context, spanCount, orientation, reverseLayout);
        this.mRecyclerView = recyclerView;
    }

    @Override
    public View onInterceptFocusSearch(View focused, int direction) {
        int spanCount = getSpanCount();
        int count = getItemCount();//获取item的总数
        int fromPos = getPosition(focused);//当前焦点的位置
        int lastVisibleItemPos = findLastVisibleItemPosition();//最新的已显示的Item的位置
        Log.i("zzz", "onInterceptFocusSearch , fromPos = " + fromPos + " , count = " + count+" , lastVisibleItemPos = "+lastVisibleItemPos);
        switch (direction) {//根据按键逻辑控制position
            case View.FOCUS_DOWN:
                fromPos += spanCount;
                break;
            case View.FOCUS_UP:
                fromPos -= spanCount;
                break;
        }
        Log.i("zzz", "after onInterceptFocusSearch , fromPos = " + fromPos + " , count = " + count+" , lastVisibleItemPos = "+lastVisibleItemPos);
        if(fromPos < 0 || fromPos >= count) {
            //如果下一个位置<0,或者超出item的总数,则返回当前的View,即焦点不动
            if (fromPos == -spanCount){
                smoothScrollToPosition(mRecyclerView,new RecyclerView.State(),0);
            }
            return focused;
        } else {
            //如果下一个位置大于最新的已显示的item,即下一个位置的View没有显示,则滑动到那个位置,让他显示,就可以获取焦点了
            smoothScrollToPosition(mRecyclerView,new RecyclerView.State(),fromPos);
        }
        return super.onInterceptFocusSearch(focused, direction);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        LinearSmoothScroller smoothScroller =
                new LinearSmoothScroller(recyclerView.getContext()) {
                    // 返回:滑过1px时经历的时间(ms)。
                    @Override
                    protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                        return 50f / displayMetrics.densityDpi;
                    }
                };

        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }
}

代码是和同事一起调试后的,有两点需要说明下:

  1. smoothScrollToPosition函数重写:改写了焦点移动时平滑的速度,把速度减慢了。
  2. fromPos == -spanCount,在焦点在返回到第一个的时候,调用重写的smoothScrollToPosition,该函数的重写也主要是为了这个时候的调用,因为在快速按上键的时候,会发现焦点在最左边的时候,最后一行会上下滑动一下,第一行显示不全,减慢移动速度可解决这个问题。

你可能感兴趣的:(移动开发,移动开发,android,java)