1、CenterFocusLinearLayoutManager 类是解决LinearLayoutManager模式下的item居中问题同时也控制了焦点乱跳问题,有多个重载构造函数,其中isLeft表示是否控制左键,其他参数就不用我说了吧。如果false表示不自己控制左键,那么将默认使用系统的规范。
isLeft默认true
isRight默认true
isUp默认false
isDown默认false
public class CenterFocusLinearLayoutManager extends LinearLayoutManager {
private int orientation = VERTICAL;
public CenterFocusLinearLayoutManager(Context context) {
super(context);
}
public CenterFocusLinearLayoutManager(Context context, boolean isLeft, boolean isRight) {
super(context);
this.isLeft = isLeft;
this.isRight = isRight;
}
public CenterFocusLinearLayoutManager(Context context, boolean isLeft, boolean isRight, boolean isDown) {
super(context);
this.isLeft = isLeft;
this.isRight = isRight;
this.isDown = isDown;
}
public CenterFocusLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
this.orientation = orientation;
}
public CenterFocusLinearLayoutManager(Context context, int orientation, boolean reverseLayout, boolean isLeft, boolean isRight) {
super(context, orientation, reverseLayout);
this.isLeft = isLeft;
this.isRight = isRight;
this.orientation = orientation;
}
public CenterFocusLinearLayoutManager(Context context, int orientation, boolean reverseLayout, boolean isLeft, boolean isRight, boolean isDown) {
super(context, orientation, reverseLayout);
this.isLeft = isLeft;
this.isRight = isRight;
this.isDown = isDown;
this.orientation = orientation;
}
public CenterFocusLinearLayoutManager(Context context, int orientation, boolean reverseLayout, boolean isLeft, boolean isRight, boolean isUp, boolean isDown) {
super(context, orientation, reverseLayout);
this.isLeft = isLeft;
this.isRight = isRight;
this.isUp = isUp;
this.isDown = isDown;
this.orientation = orientation;
}
private boolean isLeft = true;
private boolean isRight = true;
private boolean isUp = false;
private boolean isDown = false;
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
public static class CenterSmoothScroller extends LinearSmoothScroller {
CenterSmoothScroller(Context context) {
super(context);
}
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
}
private long mLastKeyDownTime = 0;
@Override
public View onInterceptFocusSearch(View focused, int direction) {
long current = System.currentTimeMillis();
if (current - mLastKeyDownTime < 500) {//延时获得焦点
return focused;
} else {
mLastKeyDownTime = current;
if (getFocusedChild() != null) {
int pos = getPosition(getFocusedChild());//这里要用这个方法
// int pos = getPosition(focused);//这里要用这个方法
int count = getItemCount();
int lastVisiblePosition = findLastVisibleItemPosition();
switch (direction) {
case View.FOCUS_LEFT:
if (isLeft) {
if (orientation == VERTICAL) {
return focused;
} else {
if (pos == 0) {
return focused;
}
}
}
break;
case View.FOCUS_RIGHT:
if (isRight) {
if (orientation == VERTICAL) {
return focused;
} else {
if (pos == count - 1) {
return focused;
}
}
}
break;
case View.FOCUS_UP:
if (isUp) {
if (orientation == VERTICAL) {
if (pos == 0) {
return focused;
}
} else {
return focused;
}
}
break;
case View.FOCUS_DOWN:
if (isDown) {
if (orientation == VERTICAL) {
if (pos == count - 1) {
return focused;
}
} else {
return focused;
}
}
break;
}
if (pos > getItemCount() - 1) {
return focused;
} else if (pos > lastVisiblePosition) {
scrollToPosition(pos);
}
}
return super.onInterceptFocusSearch(focused, direction);
}
}
}
如果想要居中的话需要写一个回调接口,在adapter中传position给activity,并在回调中加入下面代码即可
mRecyclerView.smoothScrollToPosition(position);
2、CenterFocusGridLayoutManager 类是解决GridLayoutManager模式下的item居中问题同时也控制了焦点乱跳问题,如果不居中,本人也想不到其他方法控制焦点乱跳,网上的方法都试过,没效果。
isLeft默认true
isRight默认true
isUp默认false
isDown默认false
isAlone默认false
public class CenterFocusGridLayoutManager extends GridLayoutManager {
private int spanCount;
private int orientation= VERTICAL;
public CenterFocusGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
this.spanCount = spanCount;
}
public CenterFocusGridLayoutManager(Context context, int spanCount, boolean isAlone) {
super(context, spanCount);
this.spanCount = spanCount;
this.isAlone = isAlone;
}
public CenterFocusGridLayoutManager(Context context, int spanCount, boolean isLeft, boolean isRight) {
super(context, spanCount);
this.spanCount = spanCount;
this.isLeft = isLeft;
this.isRight = isRight;
}
public CenterFocusGridLayoutManager(Context context, int spanCount, boolean isLeft, boolean isRight, boolean isDown) {
super(context, spanCount);
this.spanCount = spanCount;
this.isLeft = isLeft;
this.isRight = isRight;
this.isDown = isDown;
}
public CenterFocusGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout, boolean isLeft, boolean isRight) {
super(context, spanCount, orientation, reverseLayout);
this.spanCount = spanCount;
this.isLeft = isLeft;
this.isRight = isRight;
this.orientation = orientation;
}
public CenterFocusGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout,boolean isAlone, boolean isLeft, boolean isRight,boolean isUp, boolean isDown) {
super(context, spanCount, orientation, reverseLayout);
this.spanCount = spanCount;
this.orientation = orientation;
this.isAlone = isAlone;
this.isLeft = isLeft;
this.isRight = isRight;
this.isUp = isUp;
this.isDown = isDown;
}
private boolean isRight = true;
private boolean isLeft = true;
private boolean isUp=false;
private boolean isDown = false;
private boolean isAlone=false;
//用来控制自定义每行/每列不同个数的焦点,默认false。因为平常的就不适用了
private int[] rightPosArray;
private int[] leftPosArray;
public void setRightPosArray(int[] rightPosArray) {
this.rightPosArray = rightPosArray;
}
public void setLeftPosArray(int[] leftPosArray) {
this.leftPosArray = leftPosArray;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
public static class CenterSmoothScroller extends LinearSmoothScroller {
CenterSmoothScroller(Context context) {
super(context);
}
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
}
private long mLastKeyDownTime = 0;
@Override
public View onInterceptFocusSearch(View focused, int direction) {
long current = System.currentTimeMillis();
if (current - mLastKeyDownTime < 500) {
return focused;
} else {
mLastKeyDownTime = current;
if (getFocusedChild() != null) {
int pos = getPosition(getFocusedChild());
int lastVisibleItemPos = findLastVisibleItemPosition();
int count = getItemCount();
pos += 1;
if (direction == View.FOCUS_RIGHT) {
if (isAlone) {
for (int position : rightPosArray) {
if (pos == position) {
return focused;
}
}
} else if (isRight) {
if (orientation == VERTICAL) {
if (pos % spanCount == 0) {//|| pos==getChildCount()
return focused;
}
} else {
if (pos > count - spanCount) {
return focused;
}
}
}
} else if (direction == View.FOCUS_LEFT) {
if (isAlone) {
for (int position : leftPosArray) {
if (pos == position) {
return focused;
}
}
} else if (isLeft) {
if (orientation == VERTICAL) {
if (pos % spanCount == 1) {
return focused;
}
} else {
if (pos <= spanCount) {
return focused;
}
}
}
} else if (direction == View.FOCUS_UP) {
if (isUp) {
if (orientation == VERTICAL) {
if (pos <= spanCount) {
return focused;
}
} else {
if (pos % spanCount == 1) {
return focused;
}
}
}
} else if (direction == View.FOCUS_DOWN) {
if (isDown) {
if (orientation == VERTICAL) {
if (pos > count - spanCount) {
return focused;
}
} else {
if (pos % spanCount == 0) {
return focused;
}
}
}
}
if (pos > getItemCount()) {
return focused;
} else if (pos > lastVisibleItemPos+1) {
scrollToPosition(pos);
}
}
return super.onInterceptFocusSearch(focused, direction);
}
}
}
3、给大家一个焦点获得与失去监听的工具类(获得焦点的view会变大且可以获得边框并且可以通过回调得到选中的position)
public class KeyUtils {
public static void keyListenerBackground(final View mView){
mView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (b) {
mView.setSelected(true);
ScaleAnimation animationTwoCopy = new ScaleAnimation(1f, 1.1f, 1f, 1.1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwoCopy.setDuration(300);
animationTwoCopy.setFillAfter(true);
mView.startAnimation(animationTwoCopy);
}else {
mView.setSelected(false);
ScaleAnimation animationTwo = new ScaleAnimation(1.1f, 1f, 1.1f, 1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwo.setDuration(300);
animationTwo.setFillAfter(true);
mView.startAnimation(animationTwo);
}
}
});
}
public static void keyListenerBackground(final View mView, final View v2){
mView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (b) {
v2.setSelected(true);
ScaleAnimation animationTwoCopy = new ScaleAnimation(1f, 1.1f, 1f, 1.1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwoCopy.setDuration(300);
animationTwoCopy.setFillAfter(true);
mView.startAnimation(animationTwoCopy);
}else {
v2.setSelected(false);
ScaleAnimation animationTwo = new ScaleAnimation(1.1f, 1f, 1.1f, 1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwo.setDuration(300);
animationTwo.setFillAfter(true);
mView.startAnimation(animationTwo);
}
}
});
}
public static void keyListenerBackground(final View mView, final int position, final String type){
mView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (b) {
IGlobalCallback callback= CallbackManager.getInstance().getCallback(type);
if (callback != null) {
callback.executeCallback(position);
}
mView.setSelected(true);
ScaleAnimation animationTwoCopy = new ScaleAnimation(1f, 1.1f, 1f, 1.1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwoCopy.setDuration(300);
animationTwoCopy.setFillAfter(true);
mView.startAnimation(animationTwoCopy);
}else {
mView.setSelected(false);
ScaleAnimation animationTwo = new ScaleAnimation(1.1f, 1f, 1.1f, 1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwo.setDuration(300);
animationTwo.setFillAfter(true);
mView.startAnimation(animationTwo);
}
}
});
}
/*****************************item获得与失去焦点的监听***************************/
public static void keyListenerItem(final View mView){
mView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (b) {
mView.setSelected(true);
ScaleAnimation animationTwoCopy = new ScaleAnimation(1f, 1.02f, 1f, 1.02f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwoCopy.setDuration(300);
animationTwoCopy.setFillAfter(true);
mView.startAnimation(animationTwoCopy);
yesBorder(mView);
}else {
mView.setSelected(false);
//mView.setBackgroundResource(R.drawable.shape_select_background_false);
ScaleAnimation animationTwo = new ScaleAnimation(1.02f, 1f, 1.02f, 1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwo.setDuration(300);
animationTwo.setFillAfter(true);
mView.startAnimation(animationTwo);
noBorder(mView);
}
}
});
}
public static void keyListenerItem(final View mView, final int position, final String type){
mView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (b) {
IGlobalCallback callback=CallbackManager.getInstance().getCallback(type);
if (callback != null) {
callback.executeCallback(position);
}
ScaleAnimation animationTwoCopy = new ScaleAnimation(1f, 1.06f, 1f, 1.06f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwoCopy.setDuration(300);
animationTwoCopy.setFillAfter(true);
mView.startAnimation(animationTwoCopy);
yesBorder(mView);
}else {
ScaleAnimation animationTwo = new ScaleAnimation(1.06f, 1f, 1.06f, 1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwo.setDuration(300);
animationTwo.setFillAfter(true);
mView.startAnimation(animationTwo);
noBorder(mView);
}
}
});
}
/********************************************************/
public static void keyListenerText(final View mView){
mView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (b) {
ScaleAnimation animationTwoCopy = new ScaleAnimation(1f, 1.15f, 1f, 1.15f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwoCopy.setDuration(300);
animationTwoCopy.setFillAfter(true);
mView.startAnimation(animationTwoCopy);
yesBorder(mView);
}else {
ScaleAnimation animationTwo = new ScaleAnimation(1.15f, 1f, 1.15f, 1f, mView.getWidth() / 2, mView.getHeight() / 2);
animationTwo.setDuration(300);
animationTwo.setFillAfter(true);
mView.startAnimation(animationTwo);
noBorder(mView);
}
}
});
}
private static void yesBorder(View mView){
//创建Drawable对象
GradientDrawable drawable=new GradientDrawable();
drawable.setStroke(3, Color.parseColor("#A4D9DF"));
drawable.setColor(Color.TRANSPARENT);
drawable.setCornerRadius(6);
mView.setBackground(drawable);
}
private static void noBorder(View mView){
GradientDrawable drawable=new GradientDrawable();
drawable.setCornerRadius(6);
drawable.setColor(Color.TRANSPARENT);
mView.setBackground(drawable);
}
}