我们把RecyclerView写成GridView样式,并把RecyclerView的item写成focusable并且有焦点框的时候,我们用焦点滚动RecyclerView的时候会发现RecyclerView的焦点跳转有bug,跟我们想要的焦点跳转规则不一致,会出现的BUG如下图:
黑色方框代表屏幕,我们从左上角的一个item往下按焦点的时候,当需要加载新的一行的时候焦点却跑到了新的一行的最后一个item上面了,(如图,本来是item1获得焦点的,结果跑到item2上面了)。
这是RecyclerView的一个BUG,记得RecyclerView刚出来的时候滚动都还有点卡顿,到了现在滚动起来还是非常流畅的,比较一个全新的艺术般的空间是需要时间来沉淀的,这个BUG我们可以重写GridLayoutManger来解决。直接看代码:
package com.wasu.cs.widget;
import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
public class FocusGridLayoutManager extends GridLayoutManager {
public FocusGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public FocusGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}
public FocusGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
}
@Override
public int getChildCount() {
return super.getChildCount();
}
@Override
public View getChildAt(int index) {
return super.getChildAt(index);
}
@Override
public int getItemCount() {
return super.getItemCount();
}
@Override
public View getFocusedChild() {
return super.getFocusedChild();
}
@Override
public int getPosition(View view) {
return super.getPosition(view);
}
@Override
public int getSpanCount() {
return super.getSpanCount();
}
@Override
public View onFocusSearchFailed(View focused, int focusDirection, RecyclerView.Recycler recycler, RecyclerView.State state) {
// Need to be called in order to layout new row/column
View nextFocus = super.onFocusSearchFailed(focused, focusDirection, recycler, state);
if (nextFocus == null) {
return null;
}
int fromPos = getPosition(focused);
int nextPos = getNextViewPos(fromPos, focusDirection);
return findViewByPosition(nextPos);
}
protected int getNextViewPos(int fromPos, int direction) {
int offset = calcOffsetTonextView(direction);
if (hitBorder(fromPos, offset)) {
return fromPos;
}
return fromPos + offset;
}
protected int calcOffsetTonextView(int direction) {
int spanCount = getSpanCount();
int orientation = getOrientation();
if (orientation == VERTICAL) {
switch (direction) {
case View.FOCUS_DOWN:
return spanCount;
case View.FOCUS_UP:
return -spanCount;
case View.FOCUS_RIGHT:
return 1;
case View.FOCUS_LEFT:
return -1;
}
} else if (orientation == HORIZONTAL) {
switch (direction) {
case View.FOCUS_DOWN:
return 1;
case View.FOCUS_UP:
return -1;
case View.FOCUS_RIGHT:
return spanCount;
case View.FOCUS_LEFT:
return -spanCount;
}
}
return 0;
}
private boolean hitBorder(int from, int offset) {
int spanCount = getSpanCount();
if (Math.abs(offset) == 1) {
int spanIndex = from % spanCount;
int newSpanIndex = spanIndex + offset;
return newSpanIndex < 0 || newSpanIndex >= spanCount;
} else {
int newPos = from + offset;
return newPos < 0 && newPos >= spanCount;
}
}
}
分析:在我们从第五行往下按的时候,第六行的view是重新加载的,当新的一行的item还没有加载出来的时候,去找焦点是找不到的,找不到焦点就会调用mLayout.onFocusSearchFailed()方法,
onFocusSearchFailed方法是LayoutManager的方法,默认是返回null的,我们在自定义GridLayoutManager的时候重写此方法即可,具体的处理步骤请看到代码。在RecyclerView源代码中,onFocusSearchFailed是内部抽象类LayoutManager的一个成员方法,默认返回null。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。



