Как прокрутить до нижней части RecyclerView? scrollToPosition не работает

Я хочу прокрутить список в списке RecyclerView после загрузки активности.

GENERIC_MESSAGE_LIST = (ArrayList) intent.getExtras().getParcelableArrayList(ConversationsAdapter.EXTRA_MESSAGE);
conversationView = (RecyclerView) findViewById(R.id.list_messages);
conversationView.setHasFixedSize(true);
conversationViewLayoutManager = new LinearLayoutManager(this);
conversationView.setLayoutManager(conversationViewLayoutManager);
conversationViewAdapter = new ConversationAdapter(GENERIC_MESSAGE_LIST, this);
conversationView.setAdapter(conversationViewAdapter);

conversationView.scrollTo(...) выдает исключение из-за того, что не поддерживается в RecyclerView, а conversationView.scrollToPosition(...) ничего не делает.

После вышеописанного блока кода я добавил

conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size() + 1)

который не работает. В GENERIC_MESSAGE_LIST есть 30 элементов.

Ответ 1

Просто установите setStackFromEnd=true или setReverseLayout=true, чтобы LLM закончил элементы макета.

Разница между этими двумя заключается в том, что setStackFromEnd установит представление для отображения последнего элемента, направление макета останется прежним. (Таким образом, в горизонтальном представлении Recycler влево-вправо будет показан последний элемент, а прокрутка влево отобразит предыдущие элементы)

В то время как setReverseLayout изменит порядок элементов, добавленных адаптером. Макет будет начинаться с последнего элемента, который будет самым левым в LTR Recycler View, а затем, прокручивая вправо, отобразит более ранние элементы.

Пример:

final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
_listView.setLayoutManager(linearLayoutManager);

Подробнее см. .

Ответ 2

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

Что я использовал?

recyclerView.scrollToPosition(items.size());

... что РАБОТАЕТ?

recyclerView.scrollToPosition(items.size() - 1);

Ответ 3

Я знаю, что он опоздал, чтобы ответить здесь, но если кто-то хочет знать решение ниже

conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);

Ответ 4

Для прокрутки из любой позиции в recyclerview до нижней

edittext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rv_commentList.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                      rv_commentList.scrollToPosition(rv_commentList.getAdapter().getItemCount() - 1);
                    }
                }, 1000);
            }
        });

Ответ 5

Когда вы вызываете setAdapter, это не сразу выставляет и позиционирует элементы на экране (который принимает один проход макета), поэтому ваш вызов scrollToPosition() не имеет фактических элементов для прокрутки, когда вы его вызываете.

Вместо этого вы должны зарегистрировать ViewTreeObserver.OnGlobalLayoutListener (через addOnGlobalLayoutListner() из ViewTreeObserver, созданного conversationView.getViewTreeObserver()), который задерживает ваш scrollToPosition() до тех пор, пока не пройдет первый макет:

conversationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  public void onGlobalLayout() {
    conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size();
    // Unregister the listener to only call scrollToPosition once
    conversationView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

    // Use vto.removeOnGlobalLayoutListener(this) on API16+ devices as 
    // removeGlobalOnLayoutListener is deprecated.
    // They do the same thing, just a rename so your choice.
  }
});

Ответ 6

Добавьте этот код после отправки сообщения и до получения сообщения с сервера

recyclerView.scrollToPosition(mChatList.size() - 1);

Ответ 7

class MyLayoutManager extends LinearLayoutManager {

  public MyLayoutManager(Context context) {
    super(context, LinearLayoutManager.VERTICAL, false);
  }

  @Override public void smoothScrollToPosition(RecyclerView recyclerView,
      final RecyclerView.State state, final int position) {

    int fcvip = findFirstCompletelyVisibleItemPosition();
    int lcvip = findLastCompletelyVisibleItemPosition();

    if (position < fcvip || lcvip < position) {
      // scrolling to invisible position

      float fcviY = findViewByPosition(fcvip).getY();
      float lcviY = findViewByPosition(lcvip).getY();

      recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

        int currentState = RecyclerView.SCROLL_STATE_IDLE;

        @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

          if (currentState == RecyclerView.SCROLL_STATE_SETTLING
              && newState == RecyclerView.SCROLL_STATE_IDLE) {

            // recursive scrolling
            smoothScrollToPosition(recyclerView, state, position);
          }

          currentState = newState;
        }

        @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

          int fcvip = findFirstCompletelyVisibleItemPosition();
          int lcvip = findLastCompletelyVisibleItemPosition();

          if ((dy < 0 && fcvip == position) || (dy > 0 && lcvip == position)) {
            // stop scrolling
            recyclerView.setOnScrollListener(null);
          }
        }
      });

      if (position < fcvip) {
        // scroll up

        recyclerView.smoothScrollBy(0, (int) (fcviY - lcviY));
      } else {
        // scroll down

        recyclerView.smoothScrollBy(0, (int) (lcviY - fcviY));
      }
    } else {
      // scrolling to visible position

      float fromY = findViewByPosition(fcvip).getY();
      float targetY = findViewByPosition(position).getY();

      recyclerView.smoothScrollBy(0, (int) (targetY - fromY));
    }
  }
}

и

MyLayoutManager layoutManager = new MyLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);

RecyclerView.Adapter adapter = new YourAdapter();
recyclerView.setAdapter(adapter);

recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);

выше код работает, но он не гладкий и не крутой.

Ответ 8

ЕСЛИ у вас есть адаптер, подключенный с помощью recyclerView, просто сделайте это.

mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());

Ответ 9

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

recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);

Ответ 10

Решение для Котлина:

применять нижеприведенный код после установки "recyclerView.adapter" или после "recyclerView.adapter.notifyDataSetChanged()"

recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)

Ответ 11

Ответ Roc - отличная помощь. Я хотел бы добавить к нему небольшой блок:

mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);

Ответ 12

Это отлично работает для меня:

AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);

Ответ 13

В Котлине:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }

private fun scrollToEnd() =
        (adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)

Ответ 14

Только ответ Яна смог сделать мой RecyclerView прокруткой до указанной позиции. Тем не менее, RecyclerView не смог прокручивать потом, когда я использовал scrollToPosition(). smoothScrollToPosition() работал, но первоначальная анимация сделала слишком медленным, когда список был длинным. Причина в том, что слушатель не был удален. Я использовал код ниже, чтобы удалить текущий ViewTreeObserver, и он работал как прелесть.

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mRecyclerView.scrollToPosition(mPosition);
            mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

Ответ 15

этот код даст вам последнее сообщение первым, я думаю, что этот ответ полезен.

    mInstaList=(RecyclerView)findViewById(R.id.insta_list);
    mInstaList.setHasFixedSize(true);

    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

    mInstaList.setLayoutManager(layoutManager);
    layoutManager.setStackFromEnd(true);
    layoutManager.setReverseLayout(true);

Ответ 16

Пробовал метод @galex, он работал до рефакторинга. Поэтому я использовал ответ @yanchenko и немного изменился. Вероятно, это потому, что я вызвал прокрутку из onCreateView(), где было построено представление фрагментов (и, вероятно, не имело правильного размера).

private fun scrollPhotosToEnd(view: View) {
    view.recycler_view.viewTreeObserver.addOnGlobalLayoutListener(object :
        ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                view.recycler_view.viewTreeObserver.removeOnGlobalLayoutListener(this)
            } else {
                @Suppress("DEPRECATION")
                view.recycler_view.viewTreeObserver.removeGlobalOnLayoutListener(this)
            }
            adapter?.itemCount?.takeIf { it > 0 }?.let {
                view.recycler_view.scrollToPosition(it - 1)
            }
        }
    })
}

Вы также можете добавить проверку viewTreeObserver.isAlive как в fooobar.com/questions/18473/....

Ответ 17

Прокрутка в первый раз при первом входе в представление рециркулятора, а затем используйте linearLayoutManager.scrollToPositionWithOffset(messageHashMap.size() -1, для прокрутки вниз для прокрутки вверх положите положительное значение в минус);

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

int totalXScroldl = chatMessageBinding.rvChat.computeVerticalScrollOffset(); chatMessageBinding.rvChat.smoothScrollBy(0, Math.abs(totalXScroldl));

Ответ 18

recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.setReverseLayout(true);// Scroll to bottom
recyclerView.setLayoutManager(layoutManager);