-
Notifications
You must be signed in to change notification settings - Fork 13
Home
Fredlxy edited this page Feb 17, 2017
·
6 revisions
这是一个在TV端使用RecyclerView的一个Demo,焦点效果是通过设置背景的方式实现的,非常简单,体验也非常好。
下面总结下在TV端使用使用RecyclerView时踩过的坑:
(一)解决RecyclerView刷新数据的时候,焦点错乱问题
(1) 允许adapter设置item id;
setHasStableIds(true)
(2)adapter中复写getItemId方法;
@Override public long getItemId(int position) { return position; }
(3)RecyclerView不允许item使用动画;
setItemAnimator(null);
(二)解决长按遥控器,让RecyclerView快速滑动,焦点错乱问题
(1)重写RecyclerView的dispatchKeyEvent方法,屏蔽RecyclerView的onKeyUp事件; (2)通过FocusFind类找到view,并让view请求焦点; (3)focusFind焦点失败之后,如果是让其滑动item的宽度(左后滑动)或者高度(上下滑动),然后return true; @Override public boolean dispatchKeyEvent(KeyEvent event) { if (mInterceptLister != null && mInterceptLister.onIntercept(event)) { return true; }
boolean result = super.dispatchKeyEvent(event); View focusView = this.getFocusedChild();
if (focusView == null) { return result; } else {
if (event.getAction() == KeyEvent.ACTION_UP) { return true; } else { switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_RIGHT: View rightView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT); mLogger.i("rightView is null:" + (rightView == null)); if (rightView != null) { rightView.requestFocus(); return true; } else { return true; } case KeyEvent.KEYCODE_DPAD_LEFT: View leftView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT); mLogger.i("leftView is null:" + (leftView == null)); if (leftView != null) { leftView.requestFocus(); return true; } else { return true; } case KeyEvent.KEYCODE_DPAD_DOWN: View downView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_DOWN); mLogger.i(" downView is null:" + (downView == null)); if (downView != null) { downView.requestFocus(); return true; } else { return true; } case KeyEvent.KEYCODE_DPAD_UP: View upView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_UP); mLogger.i("upView is null:" + (upView == null)); if (event.getAction() == KeyEvent.ACTION_UP) { return true; } else { if (upView != null) { upView.requestFocus(); return true; } else { return true; }
} }
}
} return result; }
(三)解决RecyclerView 定位到某个item不获取焦点问题
RecyclerView定位到特定的child后,让其该view请求焦点
public class TvGridLayoutManager extends GridLayoutManager {
public TvGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); }
public TvGridLayoutManager(Context context, int spanCount) { super(context, spanCount); }
public TvGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, spanCount, orientation, reverseLayout); }
/** * Base class which scrolls to selected view in onStop(). */ abstract class GridLinearSmoothScroller extends LinearSmoothScroller {
public GridLinearSmoothScroller(Context context) { super(context); }
/** * 滑动完成后,让该targetPosition 处的item获取焦点 */ @Override protected void onStop() { super.onStop(); View targetView = findViewByPosition(getTargetPosition());
if (targetView != null) { targetView.requestFocus(); } super.onStop(); }
}
/** * RecyclerView的smoothScrollToPosition方法最终会执行smoothScrollToPosition * @param recyclerView * @param state * @param position */ @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { GridLinearSmoothScroller linearSmoothScroller = new GridLinearSmoothScroller(recyclerView.getContext()) { @Override public PointF computeScrollVectorForPosition(int targetPosition) { return computeVectorForPosition(targetPosition); } }; linearSmoothScroller.setTargetPosition(position); startSmoothScroll(linearSmoothScroller); }
public PointF computeVectorForPosition(int targetPosition) { return super.computeScrollVectorForPosition(targetPosition); }
}