Запустите мою горизонтальную карусель RecyclerView из центрального элемента

Я создаю карусель Horizontal RecyclerView с масштабированием на сфокусированном элементе, который начинается с первого элемента RecyclerView.

Код для пользовательского CenterZoomLayoutManager:

public class CenterZoomLayoutManager extends LinearLayoutManager {
private final float mShrinkAmount = 0.15f;
private final float mShrinkDistance = 0.9f;

public CenterZoomLayoutManager(Context context, int orientation, boolean reverseLayout) {
    super(context, orientation, reverseLayout);
}

@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
    int orientation = getOrientation();
    if (orientation == HORIZONTAL) {

        int scrolled = super.scrollHorizontallyBy(dx, recycler, state);
        float midpoint = getWidth() / 2.f;
        float d0 = 0.f;
        float d1 = mShrinkDistance * midpoint;
        float s0 = 1.f;
        float s1 = 1.f - mShrinkAmount;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            float childMidpoint =
                    (getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;
            float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
            float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
            child.setScaleX(scale);
            child.setScaleY(scale);
        }
        return scrolled;
    } else return 0;
}

@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
    super.onLayoutChildren(recycler, state);
    scrollHorizontallyBy(0, recycler, state);
}
}

И в моем Fragment у меня есть следующее:

private void onSetRecyclerView() {

    recyclerView = fragmentView.findViewById(R.id.recyclerView);

    if (recyclerView != null) {
        RecyclerView.LayoutManager layoutManager = new CenterZoomLayoutManager(context, LinearLayoutManager.HORIZONTAL,
                false);

        recyclerView.scrollToPosition(storeList.size() / 2);

        final SnapHelper snapHelper = new LinearSnapHelper();
        snapHelper.attachToRecyclerView(recyclerView);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);
    }
}

Я хочу запустить свой RecyclerView с центрального элемента, а не с начальной позиции.

Виновник:
в моем CenterZoomLayoutManager я устанавливаю начальное смещение в пикселях от 0 пикселей до scrollHorizontallyBy(0, recycler, state).

Проблема:
я не могу найти способ передать пиксели смещения, созданные recyclerView.scrollToPosition(storeList.size() / 2), в CenterZoomLayoutManager. Я пытался найти другой встроенный метод для получения X-смещения, но пока безуспешно.


person Red M    schedule 13.09.2018    source источник
comment
Вы можете помочь мне понять математику, стоящую за этим?   -  person r4jiv007    schedule 21.06.2020
comment
Я выкладывал это почти 2 года назад. Я не очень хорошо помню математическую логику, но могу сказать, что писал это не я. Я скопировал откуда-то. Вы можете скопировать его часть и поискать в сети. Вы сможете найти исходный пост. Что касается результата, я добился того, чтобы мой макет располагался по центру посередине и не был близок к горизонтальному левому или правому краю экрана после ответа @Cheticamp. Надеюсь, это поможет.   -  person Red M    schedule 22.06.2020


Ответы (1)


Решение состоит в том, чтобы изменить время, когда LinearSnapHelper присоединяется к RecyclerView. Ниже приведен переработанный onSetRecyclerView(), который будет привязывать центральный элемент RecyclerView к центру экрана. Обратите внимание, что LinearSnapHelper не прикрепляется до тех пор, пока RecyclerView не выложен и не прокручен соответствующим образом. Вам не нужно прокручивать в onLayoutChildren().

private void onSetRecyclerView() {
    recyclerView = findViewById(R.id.recyclerView);
    CenterZoomLayoutManager layoutManager =
        new CenterZoomLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(adapter);
    // Scroll to the position we want to snap to
    layoutManager.scrollToPosition(storeList.size() / 2);
    // Wait until the RecyclerView is laid out.
    recyclerView.post(new Runnable() {
        @Override
        public void run() {
            // Shift the view to snap  near the center of the screen.
            // This does not have to be precise.
            int dx = (recyclerView.getWidth() - recyclerView.getChildAt(0).getWidth()) / 2;
            recyclerView.scrollBy(-dx, 0);
            // Assign the LinearSnapHelper that will initially snap the near-center view.
            LinearSnapHelper snapHelper = new LinearSnapHelper();
            snapHelper.attachToRecyclerView(recyclerView);
        }
    });
}

Вот как отображается начальный экран моего тестового приложения. Есть 201 "магазин".

введите описание изображения здесь

person Cheticamp    schedule 16.09.2018
comment
Почему вы используете нулевой индекс для getChildAt()? - person Red M; 19.09.2018
comment
@RedM layoutManager.scrollToPosition(storeList.size() / 2) сделает достаточно, чтобы вывести центральный вид на экран. В RecyclerView это будет первый дочерний элемент или дочерний элемент с индексом 0. - person Cheticamp; 19.09.2018