RecyclerView焦点滚动

时间:2015-07-23 19:49:29

标签: android focus android-recyclerview

我有一个RecyclerView,通常有两列,最多八列。我们使用了很多D-PAD导航。滚动时我们遇到问题,焦点项目将从左向右跳跃。看照片: enter image description here

我注意到如果下一个出现的项目被缓存,滚动时没有焦点问题。我遇到的另一个问题是我的焦点项目可能出现在我的粘贴标题下方。这是不希望的。所以我觉得如果我滚动它就会有一个“阈值”。这样,当焦点位于屏幕外的一个项目内时,它将滚动。这样,焦点永远不会位于最底层或最顶层。

考虑到这一点,我尝试了这种方法,没有运气:

RecyclerView rv;

@Override
public void onFocusChange(View v, boolean hasFocus) {
    if(!v.hasFocus()) {
        Log.w(TAG, "View v did not have focus");
        return;
    }

    final int index = rv.getChildPosition(v); //adapter pos
    if(index == NO_POSITION) {
        Log.w(TAG, "Recycler view did not have view");
        return;
    }

    int position = rv.indexOfChild(v);  // layout pos
    int lastPos = rv.getChildCount();   // layout pos
    int span = getLayoutManager().getSpanCount();
    int threshold = 2 * span;
    Log.d(TAG, String.format("Position: %1$d. lastPos: %2$d. span: %3$d. threshold: %4$d", position, lastPos, span, threshold));

    if (position >= (lastPos - threshold)) {
        //scroll down if possible
        int bottomIndex = rv.getChildPosition(rv.getChildAt(lastPos));
        if (bottomIndex < getItemCount()) {
            //scroll down
            int scrollBy = v.getHeight();
            recycler.scrollBy(0, scrollBy);
            Log.d(TAG, String.format("Scrolling down by %d", scrollBy));

        }

    } else if (position <= threshold) {
        //scroll up if possible
        int topIndex = rv.getChildPosition(rv.getChildAt(0));
        if (topIndex > 0) {
            //scroll up
            int scrollBy = v.getHeight();
            recycler.scrollBy(0, -scrollBy);
            Log.d(TAG, String.format("Scrolling up by %d", -scrollBy));
        }
    }
}

我对滚动时如何管理焦点的任何想法持开放态度。

1 个答案:

答案 0 :(得分:7)

我向AOSP问题跟踪器报告了此错误:issue 190526

正如我从源代码中看到的那样,问题是GridLayoutManager使用LinearLayoutManager onFocusSearchFailed()的实现,当焦点接近{{1}的内边界时调用RecyclerView }。 LinearLayoutManager的实现仅提供第一个/最后一个(取决于滚动方向)元素。因此焦点跳转到新行的第一个/最后一个元素。

My workaround for this issue