У меня есть этот код для RecyclerView.
recyclerView = (RecyclerView)rootview.findViewById(R.id.fabric_recyclerView);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new RV_Item_Spacing(5));
FabricAdapter fabricAdapter=new FabricAdapter(ViewAdsCollection.getFabricAdsDetailsAsArray());
recyclerView.setAdapter(fabricAdapter);
Мне нужно знать, когда RecyclerView достигает самой нижней позиции при прокрутке. Является ли это возможным ? Если да, то как?
Ответы:
есть также простой способ сделать это
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (!recyclerView.canScrollVertically(1)) { Toast.makeText(YourActivity.this, "Last", Toast.LENGTH_LONG).show(); } } });
Целые числа направления: -1 для вверх, 1 для вниз, 0 всегда будет возвращать false.
источник
if (!recyclerView.canScrollVertically(1) && !mHasReachedBottomOnce) { mHasReachedBottomOnce = true Toast.makeText(YourActivity.this, "Last", Toast.LENGTH_LONG).show();}
newState == RecyclerView.SCROLL_STATE_IDLE
вif
заявление будет работать.Используйте этот код, чтобы избежать повторных вызовов
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (!recyclerView.canScrollVertically(1) && newState==RecyclerView.SCROLL_STATE_IDLE) { Log.d("-----","end"); } } });
источник
Просто реализуйте addOnScrollListener () в своем recyclerview. Затем внутри слушателя прокрутки реализуйте приведенный ниже код.
RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (mIsLoading) return; int visibleItemCount = mLayoutManager.getChildCount(); int totalItemCount = mLayoutManager.getItemCount(); int pastVisibleItems = mLayoutManager.findFirstVisibleItemPosition(); if (pastVisibleItems + visibleItemCount >= totalItemCount) { //End of list } } };
источник
'findFirstVisibleItemPosition'
наandroid.support.v7.widget.RecyclerView
(recyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
. Эта работа.Ответ на Kotlin, он будет работать на Java. IntelliJ должен преобразовать его за вас, если вы скопируете и вставите.
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener(){ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { // 3 lines below are not needed. Log.d("TAG","Last visible item is: ${gridLayoutManager.findLastVisibleItemPosition()}") Log.d("TAG","Item count is: ${gridLayoutManager.itemCount}") Log.d("TAG","end? : ${gridLayoutManager.findLastVisibleItemPosition() == gridLayoutManager.itemCount-1}") if(gridLayoutManager.findLastVisibleItemPosition() == gridLayoutManager.itemCount-1){ // We have reached the end of the recycler view. } super.onScrolled(recyclerView, dx, dy) } })
Это также будет работать,
LinearLayoutManager
потому что в нем используются те же методы, что и выше. А именноfindLastVisibleItemPosition()
иgetItemCount()
(itemCount
в Котлине).источник
Я не получил идеального решения по приведенным выше ответам, потому что он срабатывал дважды даже на
onScrolled
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) if( !recyclerView.canScrollVertically(RecyclerView.FOCUS_DOWN)) context?.toast("Scroll end reached") }
источник
recyclerView.canScrollVertically(direction)
направление - это любое целое число + vs - поэтому может быть 4, если оно внизу, или -12, если оно вверху.Попробуй это
Я использовал приведенные выше ответы, он запускается всегда, когда вы перейдете в конец просмотра ресайклера,
Если вы хотите проверить только один раз, находится ли он внизу или нет? Пример: - Если у меня есть список из 10 элементов, когда я иду вниз, он будет отображать меня, и снова, если я прокручиваю сверху вниз, он больше не будет печататься, и если вы добавите больше списков и перейдете туда, он снова будет отображаться.
Примечание. - Используйте этот метод, когда вы имеете дело со смещением при обращении к API.
Создайте класс с именем EndlessRecyclerViewScrollListener
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; public abstract class EndlessRecyclerViewScrollListener extends RecyclerView.OnScrollListener { // The minimum amount of items to have below your current scroll position // before loading more. private int visibleThreshold = 5; // The current offset index of data you have loaded private int currentPage = 0; // The total number of items in the dataset after the last load private int previousTotalItemCount = 0; // True if we are still waiting for the last set of data to load. private boolean loading = true; // Sets the starting page index private int startingPageIndex = 0; RecyclerView.LayoutManager mLayoutManager; public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) { this.mLayoutManager = layoutManager; } // public EndlessRecyclerViewScrollListener() { // this.mLayoutManager = layoutManager; // visibleThreshold = visibleThreshold * layoutManager.getSpanCount(); // } public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) { this.mLayoutManager = layoutManager; visibleThreshold = visibleThreshold * layoutManager.getSpanCount(); } public int getLastVisibleItem(int[] lastVisibleItemPositions) { int maxSize = 0; for (int i = 0; i < lastVisibleItemPositions.length; i++) { if (i == 0) { maxSize = lastVisibleItemPositions[i]; } else if (lastVisibleItemPositions[i] > maxSize) { maxSize = lastVisibleItemPositions[i]; } } return maxSize; } // This happens many times a second during a scroll, so be wary of the code you place here. // We are given a few useful parameters to help us work out if we need to load some more data, // but first we check if we are waiting for the previous load to finish. @Override public void onScrolled(RecyclerView view, int dx, int dy) { int lastVisibleItemPosition = 0; int totalItemCount = mLayoutManager.getItemCount(); if (mLayoutManager instanceof StaggeredGridLayoutManager) { int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null); // get maximum element within the list lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions); } else if (mLayoutManager instanceof GridLayoutManager) { lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition(); } else if (mLayoutManager instanceof LinearLayoutManager) { lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition(); } // If the total item count is zero and the previous isn't, assume the // list is invalidated and should be reset back to initial state if (totalItemCount < previousTotalItemCount) { this.currentPage = this.startingPageIndex; this.previousTotalItemCount = totalItemCount; if (totalItemCount == 0) { this.loading = true; } } // If it’s still loading, we check to see if the dataset count has // changed, if so we conclude it has finished loading and update the current page // number and total item count. if (loading && (totalItemCount > previousTotalItemCount)) { loading = false; previousTotalItemCount = totalItemCount; } // If it isn’t currently loading, we check to see if we have breached // the visibleThreshold and need to reload more data. // If we do need to reload some more data, we execute onLoadMore to fetch the data. // threshold should reflect how many total columns there are too if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) { currentPage++; onLoadMore(currentPage, totalItemCount, view); loading = true; } } // Call this method whenever performing new searches public void resetState() { this.currentPage = this.startingPageIndex; this.previousTotalItemCount = 0; this.loading = true; } // Defines the process for actually loading more data based on page public abstract void onLoadMore(int page, int totalItemsCount, RecyclerView view); }
используйте этот класс вот так
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener( linearLayoutManager) { @Override public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { Toast.makeText(getActivity(),"LAst",Toast.LENGTH_LONG).show(); } });
Он работает идеально с моей стороны, сообщите мне, если у вас возникнут проблемы
источник
Вот моя реализация, она очень пригодится
StaggeredGridLayout
.Применение :
private EndlessScrollListener scrollListener = new EndlessScrollListener(new EndlessScrollListener.RefreshList() { @Override public void onRefresh(int pageNumber) { //end of the list } }); rvMain.addOnScrollListener(scrollListener);
Реализация слушателя:
class EndlessScrollListener extends RecyclerView.OnScrollListener { private boolean isLoading; private boolean hasMorePages; private int pageNumber = 0; private RefreshList refreshList; private boolean isRefreshing; private int pastVisibleItems; EndlessScrollListener(RefreshList refreshList) { this.isLoading = false; this.hasMorePages = true; this.refreshList = refreshList; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); StaggeredGridLayoutManager manager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager(); int visibleItemCount = manager.getChildCount(); int totalItemCount = manager.getItemCount(); int[] firstVisibleItems = manager.findFirstVisibleItemPositions(null); if (firstVisibleItems != null && firstVisibleItems.length > 0) { pastVisibleItems = firstVisibleItems[0]; } if (visibleItemCount + pastVisibleItems >= totalItemCount && !isLoading) { isLoading = true; if (hasMorePages && !isRefreshing) { isRefreshing = true; new Handler().postDelayed(new Runnable() { @Override public void run() { refreshList.onRefresh(pageNumber); } }, 200); } } else { isLoading = false; } } public void noMorePages() { this.hasMorePages = false; } void notifyMorePages() { isRefreshing = false; pageNumber = pageNumber + 1; } interface RefreshList { void onRefresh(int pageNumber); } }
источник
Я тоже искал этот вопрос, но не нашел удовлетворительного ответа, поэтому создаю собственную реализацию recyclerView.
другие решения менее точны, чем мои. например: если последний элемент довольно большой (много текста), то обратный вызов других решений произойдет намного раньше, чем recyclerView действительно достиг дна.
мое решение исправить эту проблему.
class CustomRecyclerView: RecyclerView{ abstract class TopAndBottomListener{ open fun onBottomNow(onBottomNow:Boolean){} open fun onTopNow(onTopNow:Boolean){} } constructor(c:Context):this(c, null) constructor(c:Context, attr:AttributeSet?):super(c, attr, 0) constructor(c:Context, attr:AttributeSet?, defStyle:Int):super(c, attr, defStyle) private var linearLayoutManager:LinearLayoutManager? = null private var topAndBottomListener:TopAndBottomListener? = null private var onBottomNow = false private var onTopNow = false private var onBottomTopScrollListener:RecyclerView.OnScrollListener? = null fun setTopAndBottomListener(l:TopAndBottomListener?){ if (l != null){ checkLayoutManager() onBottomTopScrollListener = createBottomAndTopScrollListener() addOnScrollListener(onBottomTopScrollListener) topAndBottomListener = l } else { removeOnScrollListener(onBottomTopScrollListener) topAndBottomListener = null } } private fun createBottomAndTopScrollListener() = object :RecyclerView.OnScrollListener(){ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { checkOnTop() checkOnBottom() } } private fun checkOnTop(){ val firstVisible = linearLayoutManager!!.findFirstCompletelyVisibleItemPosition() if(firstVisible == 0 || firstVisible == -1 && !canScrollToTop()){ if (!onTopNow) { onTopNow = true topAndBottomListener?.onTopNow(true) } } else if (onTopNow){ onTopNow = false topAndBottomListener?.onTopNow(false) } } private fun checkOnBottom(){ var lastVisible = linearLayoutManager!!.findLastCompletelyVisibleItemPosition() val size = linearLayoutManager!!.itemCount - 1 if(lastVisible == size || lastVisible == -1 && !canScrollToBottom()){ if (!onBottomNow){ onBottomNow = true topAndBottomListener?.onBottomNow(true) } } else if(onBottomNow){ onBottomNow = false topAndBottomListener?.onBottomNow(false) } } private fun checkLayoutManager(){ if (layoutManager is LinearLayoutManager) linearLayoutManager = layoutManager as LinearLayoutManager else throw Exception("for using this listener, please set LinearLayoutManager") } private fun canScrollToTop():Boolean = canScrollVertically(-1) private fun canScrollToBottom():Boolean = canScrollVertically(1) }
затем в вашей активности / фрагменте:
override fun onCreate() { customRecyclerView.layoutManager = LinearLayoutManager(context) } override fun onResume() { super.onResume() customRecyclerView.setTopAndBottomListener(this) } override fun onStop() { super.onStop() customRecyclerView.setTopAndBottomListener(null) }
надеюсь, это поможет кому-то ;-)
источник
Не удовлетворившись большинством других ответов в этой теме, я нашел то, что, по моему мнению, лучше, и нигде здесь нет.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (!recyclerView.canScrollVertically(1) && dy > 0) { //scrolled to bottom }else if (!recyclerView.canScrollVertically(-1) && dy < 0) { //scrolled to bottom } } });
Это просто и ударит ровно один раз при любых условиях при прокрутке вверх или вниз.
источник
Это мое решение:
val onScrollListener = object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) { directionDown = dy > 0 } override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { if (recyclerView.canScrollVertically(1).not() && state != State.UPDATING && newState == RecyclerView.SCROLL_STATE_IDLE && directionDown) { state = State.UPDATING // TODO do what you want when you reach bottom, direction // is down and flag for non-duplicate execution } } }
источник
state
это перечисление?Мы можем использовать интерфейс для получения позиции
Интерфейс: создать интерфейс для слушателя
public interface OnTopReachListener { void onTopReached(int position);}
Деятельность :
mediaRecycleAdapter = new MediaRecycleAdapter(Class.this, taskList); recycle.setAdapter(mediaRecycleAdapter); mediaRecycleAdapter.setOnSchrollPostionListener(new OnTopReachListener() { @Override public void onTopReached(int position) { Log.i("Position","onTopReached "+position); } });
Адаптер:
public void setOnSchrollPostionListener(OnTopReachListener topReachListener) { this.topReachListener = topReachListener;}@Override public void onBindViewHolder(MyViewHolder holder, int position) {if(position == 0) { topReachListener.onTopReached(position);}}
источник