在使用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来设置数据。