androidTV开发---RecyclerView焦点乱跳问题

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);
    }
}

你可能感兴趣的:(androidTV,android,java)