Android, как я могу получить текущий positon на recycliewiew, который пользователь прокрутил к элементу

в моем RecyclerView у меня есть некоторые элементы, которые пользователь может прокручивать и видеть, что теперь я хочу сохранить эту позицию и прокрутить, что после этого, этот ниже код возвращает 0 всегда, и я не могу сохранить это

recyclerMarketLists.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
        recyclerViewCurrentScrolledPosition = recyclerMarketLists.getScrollY();
        Log.e("Y: ", recyclerViewCurrentSceolledPosition + "");
    }
});

Logcat:

07-07 18:28:30.919 2124-2124/com.sample.presentationproject E/Y:: 0

Ответ 1

Вы пытаетесь получить информацию о неправильном объекте. Это не RecyclerView ни Adapter ответственность, но RecyclerView LayoutManager.

Вместо универсального ViewTreeObserver.OnScrollChangedListener() я бы рекомендовал добавить вместо него RecyclerView.OnScrollListener и использовать onScrollStateChanged(RecyclerView recyclerView, int newState) который дает вам newState, для извлечения его позиции необходимо использовать SCROLL_STATE_IDLE. Имея в виду:

yourRecyclerView.getLayoutManager().findFirstVisibleItemPosition();

Как отметил Рик ван Велзен, вам, вероятно, нужно привести ваш LayoutManager к LinearLayoutManager или GridLayoutManager (вы должны привести к правильному типу, который вы используете), чтобы получить доступ к этим findVisibleXXXX().

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

RecyclerView.OnScrollListener

yigit (Google) ответ на видимых позициях

Ответ 2

Спасибо за решение Joaquim Ley. Это помогает создавать horizontal пейджер recyclerView без использования какой-либо библиотеки.

Init recyclerView

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_vocabulary_list);

    // Set up the recyclerView with the sections adapter.
    mRecyclerView = findViewById(R.id.list);
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
    mRecyclerView.setAdapter(new VocabularyListAdapter<>(vocabularyList));
    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == RecyclerView.SCROLL_STATE_IDLE){
                int position = getCurrentItem();
                onPageChanged(position);
            }
        }
    });
    PagerSnapHelper snapHelper = new PagerSnapHelper();
    snapHelper.attachToRecyclerView(mRecyclerView);
}



public boolean hasPreview() {
   return getCurrentItem() > 0;
}

public boolean hasNext() {
    return mRecyclerView.getAdapter() != null &&
            getCurrentItem() < (mRecyclerView.getAdapter().getItemCount()- 1);
}

public void preview() {
    int position = getCurrentItem();
    if (position > 0)
        setCurrentItem(position -1, true);
}

public void next() {
    RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
    if (adapter == null)
        return;

    int position = getCurrentItem();
    int count = adapter.getItemCount();
    if (position < (count -1))
        setCurrentItem(position + 1, true);
}

private int getCurrentItem(){
    return ((LinearLayoutManager)mRecyclerView.getLayoutManager())
            .findFirstVisibleItemPosition();
}

private void setCurrentItem(int position, boolean smooth){
    if (smooth)
        mRecyclerView.smoothScrollToPosition(position);
    else
        mRecyclerView.scrollToPosition(position);
}

Ответ 3

Я сделал 7 изменений в MainActivity и получил идеальные по пикселям результаты. Мой просмотрщик ВСЕГДА запоминает свое предыдущее состояние при возврате к нему из какого-либо другого действия (например, DetailActivity).

Шаг 1: Инициализируйте layoutManager следующим образом:

    // Initialize the layout manager
    moviePosterLayoutManager = (moviePosterRecyclerView.getLayoutManager() == null) ?
    new GridLayoutManager(this, numberOfColumns) :  moviePosterRecyclerView.getLayoutManager();
            // create a new layoutManager                       // reuse the existing layoutManager

Шаг 2: Внутри вашего класса MainActivity создайте переменную STATIC для хранения состояния вашего менеджера компоновки при переходе между действиями:

private static Parcelable layoutManagerState;

Шаг 3. Также создайте эту константу внутри MainActivity():

public static final String KEY_LAYOUT_MANAGER_STATE = "layoutManagerState";

Шаг 4. Внутри метода onCreate для MainActivity выполните следующий тест (т.е.

protected void onCreate(@Nullable final Bundle savedInstanceState) {....

    if (layoutManagerState != null) {
        //moviePosterLayoutManager
        moviePosterLayoutManager.onRestoreInstanceState(layoutManagerState);
        moviePosterRecyclerView.setLayoutManager(moviePosterLayoutManager);

    } else {

        moviePosterRecyclerView.setLayoutManager(moviePosterLayoutManager);
        moviePosterRecyclerView.scrollToPosition(moviePosition);
                                 // the default position

    }

Шаг 5: В вашем методе onSaveInstanceState обязательно сохраните layoutManagerState как пригодный для распаковки следующий код:

protected void onSaveInstanceState (Bundle outState) {

   layoutManagerState = moviePosterLayoutManager.onSaveInstanceState();

    // Save currently selected layout manager.            
   outState.putParcelable(KEY_LAYOUT_MANAGER_STATE,layoutManagerState);
}

Шаг 6: Поместите подобный код в метод onResume() MainActivity:

protected void onResume() {
    super.onResume();


    if (layoutManagerState != null) {
        moviePosterLayoutManager.onRestoreInstanceState(layoutManagerState);
    }

}

Шаг 7: Помните, что весь этот код был помещен в мой файл MainActivity.java. Важно помнить, что layoutManager отвечает за поддержание позиции прокрутки представления рециркулятора. Таким образом, сохранение состояния layoutManager имеет первостепенное значение. Код может быть модульным и помещен в пользовательское представление переработчика, но я обнаружил, что это проще для меня реализовать.

Ответ 4

Для аналогичного требования плюс некоторые действия, которые необходимо выполнить при изменении состояния прокрутки, я сделал это с помощью специального прослушивателя прокрутки:

'class OnScrollListener (закрытое действие val:() → Unit): RecyclerView.OnScrollListener() {

private var actionExecuted: Boolean = false
private var oldScrollPosition: Int = 0

override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
    super.onScrollStateChanged(recyclerView, newState)
    when (newState) {
        RecyclerView.SCROLL_STATE_DRAGGING -> actionExecuted = false
        RecyclerView.SCROLL_STATE_SETTLING -> actionExecuted = false
        RecyclerView.SCROLL_STATE_IDLE -> {

            val scrolledPosition =
                (recyclerView.layoutManager as? LinearLayoutManager)?.findFirstVisibleItemPosition() ?: return

            if (scrolledPosition != RecyclerView.NO_POSITION && scrolledPosition != oldScrollPosition && !actionExecuted) {
                action.invoke()
                actionExecuted = true
                oldScrollPosition = scrolledPosition
            }

        }
    }
}

} '

Это происходит из-за ранее существовавшей ошибки в RecyclerView onScroll, которая вызывает срабатывание обратного вызова 2-3 раза или даже больше. И если есть какое-то действие, которое будет выполнено несколько раз.