RecyclerView-How to know if there is 5 items to scroll? - android

I load data from internet and i'm doing pagination.
I use this code to load more data:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(!recyclerView.canScrollVertically(1)&&loading==false&&postson==false){
loading=true;
lastitem+=20;
loaddata(lastitem);
}
}
});
But this only works when recycler view reachjes the bottom and i think this might confuse the user.
I want to load more data when 5 item left.
How to do that?

Check the item count of the layout Manager (make your layout manager global), probably linear layout manager then from there compare the two Like this:
#Override
public void onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (!isRequesting) {
int visiblePicturePosition = linearLayoutManager.findLastVisibleItemPosition()
int totalItems = linearLayoutManager.getItemCount()
if (totalItems - visiblePicturePosition <= 5) {
//Do what you want here
}
}

Related

How to split large json array into pages in Android

I'm fetching json data from https://jsonplaceholder.typicode.com/photos, and want to split this data into pages so that I can implement the Android Paging Library in my app. Does anyone know how I can achieve this?
Page 1 (returns photos for id 1 to 10):
https://jsonplaceholder.typicode.com/photos?_start=0&_limit=10
Page 2 (returns photos for id 11 to 20)
https://jsonplaceholder.typicode.com/photos?_start=10&_limit=10
For paginatio you will use android jetpack
https://developer.android.com/topic/libraries/architecture/paging
Another method
get specific number of data from api and add into recyleview after that do something like below after loading your specific data again you will call further remaining specific data make a counter for counting loaded data.
getalltemlist() is a method from where u get ur json.
Reference https://www.youtube.com/watch?v=2-vZ1g_G1Zo
boolean isScrolling=false;
rView.setAdapter(adapter);
rView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int
newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL)
{
isScrolling=true;
}
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
currentitems=layoutManager.getChildCount();
totaliitems=layoutManager.getItemCount();
scrolloutitems=layoutManager.findFirstVisibleItemPosition();
if(isScrolling && (currentitems + scrolloutitems == totaliitems))
{
isScrolling=false;
getAllItemList();
}
}
});
adapter.notifyDataSetChanged();
getAllItemList();

How to perform pagination with the Litho framework?

I am implementing a Retrofit APi for getting data from the server and showing this in a RecyclerView using the Litho framework, and it's doing well. As all of us know when we have infinite data to show in recyclerview we have to implement the pagination pattern. And I know this, but I am confused how to implement this in the Litho framework. Litho the provides onScrollListener() method:
final Component component = Recycler.create(context)
.binder(recyclerBinder)
.onScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
//
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//
})
.build();
I don't know: how to use a customized EndlessRecyclerViewScrollListener for endless scrolling in Litho?
I have had success implementing the "infinite" scroll pattern leveraging the recyclerBinder within the onScrolled method of a OnScrollListener. A trivial example would be the following:
//Initialize the RecyclerBinder
recyclerBinder = new RecyclerBinder(c, new LinearLayoutInfo(getContext(), OrientationHelper.VERTICAL, false));
//Initialize a recycler component
Component component = Recycler.create(c)
.onScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// use the recyclerBinder to determine what items at what position are visible -
// (you could also use the findLastVisibleItemPosition() method depending on your implementation)
int firstVisibleItemPosition = recyclerBinder.findFirstVisibleItemPosition();
//check if it is within range relative to the current available items and is not loading (room to improve/modify logic pending use case)
if((recyclerBinder.getItemCount() - 5) <= firstVisibleItemPosition && !isLoading) {
//if so - use your service to get the next page
service.getNextPage();
}
}
})
.build();
Then in a call back method - you can insert your items starting at the item count
public void callback(List<T> results) {
int position = recyclerBinder.getItemCount();
for(T result: results) {
Component component = //assemble your component(s) ...
ComponentInfo.Builder info = ComponentInfo.create().component(component);
recyclerBinder.insertItemAt(position, info.build());
position++;
}
}

Detect if item is visible in recyclerview from adapter [duplicate]

I need to know which elements are currently displayed in my RecyclerView. There is no equivalent to the OnScrollListener.onScroll(...) method on ListViews. I tried to work with View.getGlobalVisibleRect(...), but that hack is too ugly and does not always work too.
Someone any ideas?
First / last visible child depends on the LayoutManager.
If you are using LinearLayoutManager or GridLayoutManager, you can use
int findFirstVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
For example:
GridLayoutManager layoutManager = ((GridLayoutManager)mRecyclerView.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
For LinearLayoutManager, first/last depends on the adapter ordering. Don't query children from RecyclerView; LayoutManager may prefer to layout more items than visible for caching.
For those who have a logic to be implemented inside the RecyclerView adapter, you can still use the #ernesto approach combined with an on scrollListener to get what you want as the RecyclerView is consulted.
Inside the adapter you will have something like this:
#Override
public void onAttachedToRecyclerView(#NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if(manager instanceof LinearLayoutManager && getItemCount() > 0) {
LinearLayoutManager llm = (LinearLayoutManager) manager;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visiblePosition = llm.findFirstCompletelyVisibleItemPosition();
if(visiblePosition > -1) {
View v = llm.findViewByPosition(visiblePosition);
//do something
v.setBackgroundColor(Color.parseColor("#777777"));
}
}
});
}
}
Finally, I found a solution to know if the current item is visible, from the onBindViewHolder event in the adapter.
The key is the method isViewPartiallyVisible from LayoutManager.
In your adapter, you can get the LayoutManager from the RecyclerView, which you get as parameter from the onAttachedToRecyclerView event.
You can use recyclerView.getChildAt() to get each visible child, and setting some tag convertview.setTag(index) on these view in adapter code will help you to relate it with adapter data.
Addendum:
The proposed functions findLast...Position() do not work correctly in a scenario with a collapsing toolbar while the toolbar is expanded.
It seems that the recycler view has a fixed height, and while the toolbar is expanded, the recycler is moved down, partially out of the screen. As a consequence the results of the proposed functions are too high. Example: The last visible item is told to be #9, but in fact item #7 is the last one that is on screen.
This behaviour is also the reason why my view often failed to scroll to the correct position, i.e. scrollToPosition() did not work correctly (I finally collapsed the toolbar programmatically).
Every answer above is correct and I would like to add also a snapshot from my working codes.
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// Some code when initially scrollState changes
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Some code while the list is scrolling
LinearLayoutManager lManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstElementPosition = lManager.findFirstVisibleItemPosition();
}
});
Following Linear / Grid LayoutManager methods can be used to check which items are visible.
int findFirstVisibleItemPosition();
int findLastVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
and if you want to track is item visible on screen for some threshold then you can refer to the following blog.
https://proandroiddev.com/detecting-list-items-perceived-by-user-8f164dfb1d05
For StaggeredGridLayoutManager do this:
RecyclerView rv = findViewById(...);
StaggeredGridLayoutManager lm = new StaggeredGridLayoutManager(...);
rv.setLayoutManager(lm);
And to get visible item views:
int[] viewsIds = lm.findFirstCompletelyVisibleItemPositions(null);
ViewHolder firstViewHolder = rvPlantios.findViewHolderForLayoutPosition(viewsIds[0]);
View itemView = viewHolder.itemView;
Remember to check if it is empty.
You can find the first and last visible children of the recycle view and check if the view you're looking for is in the range:
var visibleChild: View = rv.getChildAt(0)
val firstChild: Int = rv.getChildAdapterPosition(visibleChild)
visibleChild = rv.getChildAt(rv.childCount - 1)
val lastChild: Int = rv.getChildAdapterPosition(visibleChild)
println("first visible child is: $firstChild")
println("last visible child is: $lastChild")
For those who are looking for an answer in Kotlin:
fun getVisibleItem(recyclerView : RecyclerView) {
recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
val index = (recyclerView.layoutManager.findFirstVisibleItemPosition
//use this index for any operation you want to perform on the item visible on screen. eg. log(arrayList[index])
}
}
})
}
You can explore other methods for getting the position as per your use case.
int findFirstCompletelyVisibleItemPosition()
int findLastVisibleItemPosition()
int findLastCompletelyVisibleItemPosition()
if the visible item position is different from the item position toast message will show on the screen.
myRecyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
LinearLayoutManager manager= (LinearLayoutManager) myRecyclerview.getLayoutManager();
assert manager != null;
int visiblePosition = manager.findLastCompletelyVisibleItemPosition();
if(visiblePosition > -1&&a!=visiblePosition) {
Toast.makeText(context,String.valueOf(visiblePosition),Toast.LENGTH_SHORT).show();
//do something
a=visiblePosition;
}
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//Some code while the list is scrolling
}
});

How do I get the centre item in RecyclerView [duplicate]

I need to know which elements are currently displayed in my RecyclerView. There is no equivalent to the OnScrollListener.onScroll(...) method on ListViews. I tried to work with View.getGlobalVisibleRect(...), but that hack is too ugly and does not always work too.
Someone any ideas?
First / last visible child depends on the LayoutManager.
If you are using LinearLayoutManager or GridLayoutManager, you can use
int findFirstVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
For example:
GridLayoutManager layoutManager = ((GridLayoutManager)mRecyclerView.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
For LinearLayoutManager, first/last depends on the adapter ordering. Don't query children from RecyclerView; LayoutManager may prefer to layout more items than visible for caching.
For those who have a logic to be implemented inside the RecyclerView adapter, you can still use the #ernesto approach combined with an on scrollListener to get what you want as the RecyclerView is consulted.
Inside the adapter you will have something like this:
#Override
public void onAttachedToRecyclerView(#NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if(manager instanceof LinearLayoutManager && getItemCount() > 0) {
LinearLayoutManager llm = (LinearLayoutManager) manager;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visiblePosition = llm.findFirstCompletelyVisibleItemPosition();
if(visiblePosition > -1) {
View v = llm.findViewByPosition(visiblePosition);
//do something
v.setBackgroundColor(Color.parseColor("#777777"));
}
}
});
}
}
Finally, I found a solution to know if the current item is visible, from the onBindViewHolder event in the adapter.
The key is the method isViewPartiallyVisible from LayoutManager.
In your adapter, you can get the LayoutManager from the RecyclerView, which you get as parameter from the onAttachedToRecyclerView event.
You can use recyclerView.getChildAt() to get each visible child, and setting some tag convertview.setTag(index) on these view in adapter code will help you to relate it with adapter data.
Addendum:
The proposed functions findLast...Position() do not work correctly in a scenario with a collapsing toolbar while the toolbar is expanded.
It seems that the recycler view has a fixed height, and while the toolbar is expanded, the recycler is moved down, partially out of the screen. As a consequence the results of the proposed functions are too high. Example: The last visible item is told to be #9, but in fact item #7 is the last one that is on screen.
This behaviour is also the reason why my view often failed to scroll to the correct position, i.e. scrollToPosition() did not work correctly (I finally collapsed the toolbar programmatically).
Every answer above is correct and I would like to add also a snapshot from my working codes.
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// Some code when initially scrollState changes
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Some code while the list is scrolling
LinearLayoutManager lManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstElementPosition = lManager.findFirstVisibleItemPosition();
}
});
Following Linear / Grid LayoutManager methods can be used to check which items are visible.
int findFirstVisibleItemPosition();
int findLastVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
and if you want to track is item visible on screen for some threshold then you can refer to the following blog.
https://proandroiddev.com/detecting-list-items-perceived-by-user-8f164dfb1d05
For StaggeredGridLayoutManager do this:
RecyclerView rv = findViewById(...);
StaggeredGridLayoutManager lm = new StaggeredGridLayoutManager(...);
rv.setLayoutManager(lm);
And to get visible item views:
int[] viewsIds = lm.findFirstCompletelyVisibleItemPositions(null);
ViewHolder firstViewHolder = rvPlantios.findViewHolderForLayoutPosition(viewsIds[0]);
View itemView = viewHolder.itemView;
Remember to check if it is empty.
You can find the first and last visible children of the recycle view and check if the view you're looking for is in the range:
var visibleChild: View = rv.getChildAt(0)
val firstChild: Int = rv.getChildAdapterPosition(visibleChild)
visibleChild = rv.getChildAt(rv.childCount - 1)
val lastChild: Int = rv.getChildAdapterPosition(visibleChild)
println("first visible child is: $firstChild")
println("last visible child is: $lastChild")
For those who are looking for an answer in Kotlin:
fun getVisibleItem(recyclerView : RecyclerView) {
recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
val index = (recyclerView.layoutManager.findFirstVisibleItemPosition
//use this index for any operation you want to perform on the item visible on screen. eg. log(arrayList[index])
}
}
})
}
You can explore other methods for getting the position as per your use case.
int findFirstCompletelyVisibleItemPosition()
int findLastVisibleItemPosition()
int findLastCompletelyVisibleItemPosition()
if the visible item position is different from the item position toast message will show on the screen.
myRecyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
LinearLayoutManager manager= (LinearLayoutManager) myRecyclerview.getLayoutManager();
assert manager != null;
int visiblePosition = manager.findLastCompletelyVisibleItemPosition();
if(visiblePosition > -1&&a!=visiblePosition) {
Toast.makeText(context,String.valueOf(visiblePosition),Toast.LENGTH_SHORT).show();
//do something
a=visiblePosition;
}
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//Some code while the list is scrolling
}
});

Get visible items in RecyclerView

I need to know which elements are currently displayed in my RecyclerView. There is no equivalent to the OnScrollListener.onScroll(...) method on ListViews. I tried to work with View.getGlobalVisibleRect(...), but that hack is too ugly and does not always work too.
Someone any ideas?
First / last visible child depends on the LayoutManager.
If you are using LinearLayoutManager or GridLayoutManager, you can use
int findFirstVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
For example:
GridLayoutManager layoutManager = ((GridLayoutManager)mRecyclerView.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
For LinearLayoutManager, first/last depends on the adapter ordering. Don't query children from RecyclerView; LayoutManager may prefer to layout more items than visible for caching.
For those who have a logic to be implemented inside the RecyclerView adapter, you can still use the #ernesto approach combined with an on scrollListener to get what you want as the RecyclerView is consulted.
Inside the adapter you will have something like this:
#Override
public void onAttachedToRecyclerView(#NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if(manager instanceof LinearLayoutManager && getItemCount() > 0) {
LinearLayoutManager llm = (LinearLayoutManager) manager;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visiblePosition = llm.findFirstCompletelyVisibleItemPosition();
if(visiblePosition > -1) {
View v = llm.findViewByPosition(visiblePosition);
//do something
v.setBackgroundColor(Color.parseColor("#777777"));
}
}
});
}
}
Finally, I found a solution to know if the current item is visible, from the onBindViewHolder event in the adapter.
The key is the method isViewPartiallyVisible from LayoutManager.
In your adapter, you can get the LayoutManager from the RecyclerView, which you get as parameter from the onAttachedToRecyclerView event.
You can use recyclerView.getChildAt() to get each visible child, and setting some tag convertview.setTag(index) on these view in adapter code will help you to relate it with adapter data.
Addendum:
The proposed functions findLast...Position() do not work correctly in a scenario with a collapsing toolbar while the toolbar is expanded.
It seems that the recycler view has a fixed height, and while the toolbar is expanded, the recycler is moved down, partially out of the screen. As a consequence the results of the proposed functions are too high. Example: The last visible item is told to be #9, but in fact item #7 is the last one that is on screen.
This behaviour is also the reason why my view often failed to scroll to the correct position, i.e. scrollToPosition() did not work correctly (I finally collapsed the toolbar programmatically).
Every answer above is correct and I would like to add also a snapshot from my working codes.
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// Some code when initially scrollState changes
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Some code while the list is scrolling
LinearLayoutManager lManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstElementPosition = lManager.findFirstVisibleItemPosition();
}
});
Following Linear / Grid LayoutManager methods can be used to check which items are visible.
int findFirstVisibleItemPosition();
int findLastVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
and if you want to track is item visible on screen for some threshold then you can refer to the following blog.
https://proandroiddev.com/detecting-list-items-perceived-by-user-8f164dfb1d05
For StaggeredGridLayoutManager do this:
RecyclerView rv = findViewById(...);
StaggeredGridLayoutManager lm = new StaggeredGridLayoutManager(...);
rv.setLayoutManager(lm);
And to get visible item views:
int[] viewsIds = lm.findFirstCompletelyVisibleItemPositions(null);
ViewHolder firstViewHolder = rvPlantios.findViewHolderForLayoutPosition(viewsIds[0]);
View itemView = viewHolder.itemView;
Remember to check if it is empty.
You can find the first and last visible children of the recycle view and check if the view you're looking for is in the range:
var visibleChild: View = rv.getChildAt(0)
val firstChild: Int = rv.getChildAdapterPosition(visibleChild)
visibleChild = rv.getChildAt(rv.childCount - 1)
val lastChild: Int = rv.getChildAdapterPosition(visibleChild)
println("first visible child is: $firstChild")
println("last visible child is: $lastChild")
For those who are looking for an answer in Kotlin:
fun getVisibleItem(recyclerView : RecyclerView) {
recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
val index = (recyclerView.layoutManager.findFirstVisibleItemPosition
//use this index for any operation you want to perform on the item visible on screen. eg. log(arrayList[index])
}
}
})
}
You can explore other methods for getting the position as per your use case.
int findFirstCompletelyVisibleItemPosition()
int findLastVisibleItemPosition()
int findLastCompletelyVisibleItemPosition()
if the visible item position is different from the item position toast message will show on the screen.
myRecyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
LinearLayoutManager manager= (LinearLayoutManager) myRecyclerview.getLayoutManager();
assert manager != null;
int visiblePosition = manager.findLastCompletelyVisibleItemPosition();
if(visiblePosition > -1&&a!=visiblePosition) {
Toast.makeText(context,String.valueOf(visiblePosition),Toast.LENGTH_SHORT).show();
//do something
a=visiblePosition;
}
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//Some code while the list is scrolling
}
});

Categories

Resources