Горизонтальный ScrollView внутри Vertical RecyclerView внутри Горизонтальный режим прокрутки RecyclerView - PullRequest
0 голосов
/ 07 ноября 2018

У меня есть Activity ниже:

<RecyclerView> // with horizontal LinearLayoutManager and PagerSnapHelper
    <RecyclerView> // with vertical LinearLayoutManager
        <RecyclcerView /> // with horizontal LinearLayoutManager
        <HorizontalScrollView />
        // ... and there are other normal list items
    </RecyclerView>
    <RecyclerView> // another RV with vertical LinearLayoutManager
    </RecyclerView>
</RecyclerView>

Проблема в том, что при горизонтальной прокрутке внутренняя горизонтальная RecyclerView и HorizontalScrollView не прокручиваются должным образом.

Почему я должен это сделать:

У меня есть несколько ListFragment с, каждый из которых получает данные из разных источников данных, но имеет элементы списка одного типа. Я не хочу ViewPager, который либо удерживает все страницы сразу после создания ViewPager (что может вызвать OutOfMemoryError), либо перезагружает данные из сети после прокрутки пользователем на другие страницы и прокрутки назад. Более того, с помощью вложенного RV страницы могут совместно использовать один и тот же RecyclerViewPool, что помогает уменьшить общее количество просмотров элементов на всех страницах.

Что я сделал во внешнем горизонтальном RV:

private static final int INVALID_POINTER = -1;
private int mActivePointerId = INVALID_POINTER;
private float lastX;
private GestureDetector mVerticalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return Math.abs(distanceX) < Math.abs(distanceY);
    }
});
private GestureDetector mHorizontalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return Math.abs(distanceX) > Math.abs(distanceY);
    }
});

@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
    if (mVerticalScrollGestureDetector.onTouchEvent(e) || !mAllowPageScroll) {
        return false;
    }
    switch (e.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mActivePointerId = e.getPointerId(0);
            break;
        case MotionEvent.ACTION_MOVE:
            int pointerIndex = e.findPointerIndex(mActivePointerId);
            float x = e.getX(pointerIndex);
            float dx = x - lastX;
            lastX = x;
            if (childCanScroll(this, false, (int) dx, (int) x)) {
                Log.d("ScrollX", "not intercept");
                return false;
            }
            Log.d("ScrollX", "maybe intercept");
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            mActivePointerId = INVALID_POINTER;
            break;
    }
    return super.onInterceptTouchEvent(e);
}

private boolean childCanScroll(View v, boolean considerSelf, int dx, int x) {
    if (v instanceof ViewGroup) {
        ViewGroup group = (ViewGroup) v;
        int scrollX = v.getScrollX();
        for (int i = group.getChildCount() - 1; i >= 0; i--) {
            View child = group.getChildAt(i);
            if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
                    && childCanScroll(child, true, dx, x + scrollX - child.getLeft())) {
                return true;
            }
        }
    }
    return considerSelf && v.canScrollHorizontally(-dx);
}

Теперь он работает с внутренним горизонтальным RV с , иногда без прокрутки , а вообще не работает с HorizontalScrollView .

Как мне достичь цели, чтобы сделать горизонтальный прокручиваемый вид для прокрутки первым?

1 Ответ

0 голосов
/ 13 ноября 2018

Я делаю две ошибки.

  1. В случае ACTION_DOWN мне нужно записать переменную lastX, а также в случае ACTION_MOVE, чтобы первый шаг dx был правильным значением. Это объясняет, почему метод childCanScroll не работает с такими вещами, как ScrollView (поскольку RecyclerView getScrollX() всегда возвращает 0).

  2. В методе childCanScroll внутренний оператор if должен учитывать не только координату x, но и координату y. Если y не учитывается, когда я прокручиваю за пределами внутренних горизонтальных прокручиваемых видов, метод также возвращает true, что заставляет вещи работать неправильно.

После того, как я исправлю эти две ошибки, все будет правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...