Mam ten kod dla 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);
Muszę wiedzieć, kiedy podczas przewijania RecyclerView osiąga najniższe położenie. Czy to możliwe ? Jeśli tak, w jaki sposób?
android
scroll
android-recyclerview
Adrian
źródło
źródło
Odpowiedzi:
jest też na to prosty sposób
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(); } } });
Kierunek liczby całkowite: -1 dla góry, 1 dla dołu, 0 zawsze zwróci fałsz.
źródło
if (!recyclerView.canScrollVertically(1) && !mHasReachedBottomOnce) { mHasReachedBottomOnce = true Toast.makeText(YourActivity.this, "Last", Toast.LENGTH_LONG).show();}
newState == RecyclerView.SCROLL_STATE_IDLE
doif
instrukcji zadziała.Użyj tego kodu, aby uniknąć powtarzających się połączeń
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"); } } });
źródło
Po prostu zaimplementuj addOnScrollListener () w swoim widoku recyklingu. Następnie wewnątrz odbiornika przewijania zaimplementuj poniższy kod.
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 } } };
źródło
'findFirstVisibleItemPosition'
dniuandroid.support.v7.widget.RecyclerView
(recyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
. Ta praca.Odpowiedź jest w Kotlinie, będzie działać w Javie. IntelliJ powinien przekonwertować go za Ciebie, jeśli skopiujesz i wkleisz.
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) } })
To również zadziała,
LinearLayoutManager
ponieważ ma te same metody, co powyżej. MianowiciefindLastVisibleItemPosition()
igetItemCount()
(itemCount
w Kotlinie).źródło
Powyższe odpowiedzi nie dawały mi idealnego rozwiązania, ponieważ uruchamiały się dwukrotnie
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") }
źródło
recyclerView.canScrollVertically(direction)
kierunek to dowolna liczba całkowita + vs - więc może wynosić 4, jeśli jest na dole, lub -12, jeśli jest na górze.Spróbuj tego
Skorzystałem z powyższych odpowiedzi, działa zawsze, gdy pójdziesz na koniec widoku recyklera,
Jeśli chcesz sprawdzić tylko raz, czy jest na dole, czy nie? Przykład: - Jeśli mam listę 10 pozycji za każdym razem, gdy przejdę na dół, wyświetli się ona i ponownie, jeśli przewinę z góry na dół, nie będzie drukowana ponownie, a jeśli dodasz więcej list i przejdziesz tam, zostanie ponownie wyświetlona.
Uwaga: - Użyj tej metody, gdy masz do czynienia z przesunięciem w uderzaniu API
Utwórz klasę o nazwie 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); }
użyj tej klasy w ten sposób
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(); } });
Z mojego punktu widzenia działa idealnie, pochwal mnie, jeśli masz jakiś problem
źródło
Oto moja realizacja, która jest bardzo przydatna
StaggeredGridLayout
.Stosowanie :
private EndlessScrollListener scrollListener = new EndlessScrollListener(new EndlessScrollListener.RefreshList() { @Override public void onRefresh(int pageNumber) { //end of the list } }); rvMain.addOnScrollListener(scrollListener);
Implementacja słuchacza:
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); } }
źródło
Po tym, jak nie byłem zadowolony z większości innych odpowiedzi w tym wątku, znalazłem coś, co moim zdaniem jest lepsze i nigdzie nie ma.
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 } } });
Jest to proste i nastąpi dokładnie raz w każdych warunkach, gdy przewiniesz w górę lub w dół.
źródło
Szukałem również tego pytania, ale nie znalazłem odpowiedzi, która by mnie satysfakcjonowała, dlatego tworzę własną realizację recyclinglerView.
inne rozwiązania są mniej precyzyjne niż moje. na przykład: jeśli ostatni element jest dość duży (dużo tekstu), to wywołanie zwrotne innych rozwiązań nastąpi znacznie wcześniej, niż recykllerView naprawdę osiągnął dno.
moje rozwiązanie rozwiązuje ten problem.
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) }
następnie w swoim działaniu / fragmencie:
override fun onCreate() { customRecyclerView.layoutManager = LinearLayoutManager(context) } override fun onResume() { super.onResume() customRecyclerView.setTopAndBottomListener(this) } override fun onStop() { super.onStop() customRecyclerView.setTopAndBottomListener(null) }
mam nadzieję, że komuś pomoże ;-)
źródło
To jest moje rozwiązanie:
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 } } }
źródło
state
to enum?Możemy użyć interfejsu do uzyskania pozycji
Interfejs: utwórz interfejs dla słuchacza
public interface OnTopReachListener { void onTopReached(int position);}
Czynność :
mediaRecycleAdapter = new MediaRecycleAdapter(Class.this, taskList); recycle.setAdapter(mediaRecycleAdapter); mediaRecycleAdapter.setOnSchrollPostionListener(new OnTopReachListener() { @Override public void onTopReached(int position) { Log.i("Position","onTopReached "+position); } });
Adapter:
public void setOnSchrollPostionListener(OnTopReachListener topReachListener) { this.topReachListener = topReachListener;}@Override public void onBindViewHolder(MyViewHolder holder, int position) {if(position == 0) { topReachListener.onTopReached(position);}}
źródło