Tengo este código para un 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);
Necesito saber cuándo el RecyclerView alcanza la posición más inferior mientras me desplazo. Es posible ? Si es así, ¿cómo?
android
scroll
android-recyclerview
Adrian
fuente
fuente
Respuestas:
también hay una forma sencilla de hacerlo
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(); } } });
enteros de dirección: -1 para arriba, 1 para abajo, 0 siempre devolverá falso.
fuente
if (!recyclerView.canScrollVertically(1) && !mHasReachedBottomOnce) { mHasReachedBottomOnce = true Toast.makeText(YourActivity.this, "Last", Toast.LENGTH_LONG).show();}
newState == RecyclerView.SCROLL_STATE_IDLE
en laif
declaración funcionaría.Utilice este código para evitar llamadas repetidas
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"); } } });
fuente
Simplemente implemente un addOnScrollListener () en su vista de reciclaje. Luego, dentro del oyente de desplazamiento, implemente el siguiente código.
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 } } };
fuente
'findFirstVisibleItemPosition'
enandroid.support.v7.widget.RecyclerView
(recyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
. Este trabajo.La respuesta está en Kotlin, funcionará en Java. IntelliJ debería convertirlo por usted si copia y pega.
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) } })
Esto también funcionará
LinearLayoutManager
porque tiene los mismos métodos utilizados anteriormente. A saberfindLastVisibleItemPosition()
ygetItemCount()
(itemCount
en Kotlin).fuente
No estaba obteniendo una solución perfecta con las respuestas anteriores porque se activaba dos veces incluso en
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") }
fuente
recyclerView.canScrollVertically(direction)
dirección es cualquier número entero + vs, por lo que puede 4 si está en la parte inferior o -12 si está en la parte superior.Prueba esto
He usado las respuestas anteriores, se ejecuta siempre cuando irá al final de la vista del reciclador,
¿Si desea comprobar solo una vez si está en un fondo o no? Ejemplo: - Si tengo la lista de 10 elementos cada vez que voy en la parte inferior, me mostrará y nuevamente si me desplazo de arriba a abajo no se imprimirá nuevamente, y si agrega más listas y va allí, se mostrará nuevamente.
Nota: - Utilice este método cuando se ocupe de la compensación al presionar API
Cree una clase llamada 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); }
usa esta clase como esta
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(); } });
Está funcionando perfecto al final, comuníquese conmigo si tiene algún problema
fuente
Ahí está mi implementación, es muy útil para
StaggeredGridLayout
.Uso:
private EndlessScrollListener scrollListener = new EndlessScrollListener(new EndlessScrollListener.RefreshList() { @Override public void onRefresh(int pageNumber) { //end of the list } }); rvMain.addOnScrollListener(scrollListener);
Implementación del oyente:
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); } }
fuente
También estaba buscando esta pregunta, pero no encontré la respuesta que me satisficiera, así que creo una realización propia de recyclingView.
otras soluciones son menos precisas que la mía. por ejemplo: si el último elemento es bastante grande (gran cantidad de texto), la devolución de llamada de otras soluciones llegará mucho antes, y luego que el control de reciclaje realmente llegó al final.
mi solución soluciona este problema.
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) }
luego en tu actividad / fragmento:
override fun onCreate() { customRecyclerView.layoutManager = LinearLayoutManager(context) } override fun onResume() { super.onResume() customRecyclerView.setTopAndBottomListener(this) } override fun onStop() { super.onStop() customRecyclerView.setTopAndBottomListener(null) }
espero que ayude a alguien ;-)
fuente
Después de no estar satisfecho con la mayoría de las otras respuestas en este hilo, encontré algo que creo que es mejor y no está en ninguna parte aquí.
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 } } });
Esto es simple y se activará exactamente una vez en todas las condiciones cuando se haya desplazado hacia la parte superior o inferior.
fuente
Esta es mi solución:
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 } } }
fuente
state
sacaste esa enumeración?Podemos usar la interfaz para obtener la posición.
Interfaz: crea una interfaz para el oyente
public interface OnTopReachListener { void onTopReached(int position);}
Actividad :
mediaRecycleAdapter = new MediaRecycleAdapter(Class.this, taskList); recycle.setAdapter(mediaRecycleAdapter); mediaRecycleAdapter.setOnSchrollPostionListener(new OnTopReachListener() { @Override public void onTopReached(int position) { Log.i("Position","onTopReached "+position); } });
Adaptador:
public void setOnSchrollPostionListener(OnTopReachListener topReachListener) { this.topReachListener = topReachListener;}@Override public void onBindViewHolder(MyViewHolder holder, int position) {if(position == 0) { topReachListener.onTopReached(position);}}
fuente