一、问题背景
之前TV端开发遇到的一个问题,RV显示的方式是GridLayoutManager,三列,方向是:VERTICAL,也就是三列显示,上下移动。但是在快速按下键的时候,焦点在最后一排后会跳到旁边的RV上,焦点自动跳走了。要求肯定是移动到最下方的时候,焦点就在最下边呆着,界面如下图:
二、解决方案
参考链接: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);
}
}
代码是和同事一起调试后的,有两点需要说明下:
- smoothScrollToPosition函数重写:改写了焦点移动时平滑的速度,把速度减慢了。
- fromPos == -spanCount,在焦点在返回到第一个的时候,调用重写的smoothScrollToPosition,该函数的重写也主要是为了这个时候的调用,因为在快速按上键的时候,会发现焦点在最左边的时候,最后一行会上下滑动一下,第一行显示不全,减慢移动速度可解决这个问题。