I'm using RecyclerView on my Android App. I want to show firstly bottom and scroll from bottom to top. I can did it but I want to add Scroll Listener and when the scroll position on top I call a function.
chatRecycler = (RecyclerView) findViewById(R.id.chatRecycler);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
chatRecycler.setLayoutManager(layoutManager);
chatRecycler.setItemAnimator(new DefaultItemAnimator());
And I try that but it's not working. This code call the function to bottom:
chatRecycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!recyclerView.canScrollVertically(1) && newState==RecyclerView.SCROLL_STATE_IDLE) {
pageId++;
chatDuoPresenter.getChatData(pageId);
}
}
});
Edit:
I'm still searching solution.
Solution:
#Override
public void initScrollListener() {
chatRecycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0) {
pageId++;
chatDuoPresenter.getChatData(pageId);
}
}
});
}
Related
I have a RecyclerView with Horizontal LinearLayoutManager.
I would like to check ScrollListener.
My goal is to check these steps:
Check when RecyclerView start scroll
Check when RecyclerView end scroll
Check when RecyclerView's scroll is in center position
Here is a my RecyclerView code with LinearLayoutManager.
LinearLayoutManager horizontalManager = new LinearLayoutManager(context);
horizontalManager.setOrientation(LinearLayoutManager.HORIZONTAL);
viewHolderStory.recyclerView.setLayoutManager(horizontalManager);
viewHolderStory.recyclerView.addItemDecoration(new PaddingItemDecoration((Activity) context));
viewHolderStory.recyclerView.setHasFixedSize(true);
viewHolderStory.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
viewHolderStory.recyclerView.setNestedScrollingEnabled(false);
Is any way to add validation on my addOnScrollListener method?
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState==RecyclerView.SCROLL_STATE_IDLE){
/// User Stops Scroll
}
if(newState==RecyclerView.SCROLL_STATE_DRAGGING){
/// User Starts Scroll
}
}
You can find more from this.
You can compute this with computeVerticalScrollExtent() , computeVerticalScrollOffset() and computeVerticalScrollRange()
if your recyler view is horizontal, these functions have a horizontal counterpart
full code :
viewHolderStory.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
int extent = recyclerView.computeVerticalScrollExtent();
int offset = recyclerView.computeVerticalScrollOffset();
int range = recyclerView.computeVerticalScrollRange();
if(offset == 0){
//fire when recycler view hit top
Log.i("myTag", "onScrolled: top");
}
else if(offset + extent == range){
//fire when recycler view hit bottom
Log.i("myTag", "onScrolled: bottom");
}
else {
//fire the rest of the time
Log.i("myTag", "onScrolled: middle");
}
}
});
I have a recycleView that I need to observe when the last item is reached but I have notice the it always indicate that I reached the last item even if I haven't scrolled yet.
My code for setting up the recycler:
newsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
newsRecyclerView.setFocusable(false);
newsRecyclerView.setNestedScrollingEnabled(false);
newsAdapter = new NewsAdapter(getContext(), newsDetails, categoryNumber);
newsRecyclerView.setAdapter(newsAdapter);
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
My xml code is:
<android.support.v7.widget.RecyclerView
android:id="#+id/news_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/news_top_stories_title_text_view" />
This is my code that I put in my Util, and use anywhere.
Util.setRecyclerViewLastPositionListner(rv, linearLayoutManager , new UtilitiesV2.OnLastPositionReached() {
#Override
public void onReached() {
// last position reached
}
});
Put this in Util.
private boolean userScrolled = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;
public interface OnLastPositionReached {
void onReached();
}
public void setRecyclerViewLastPositionListner(RecyclerView rvBooksMockTest, final LinearLayoutManager mLayoutManager, final OnLastPositionReached onLastPositionReached) {
rvBooksMockTest.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
userScrolled = true;
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Here get the child count, item count and visibleitems
// from layout manager
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
// Now check if userScrolled is true and also check if
// the item is end then update recycler view and set
// userScrolled to false
if (userScrolled && (visibleItemCount + pastVisiblesItems) == totalItemCount) {
userScrolled = false;
if (onLastPositionReached != null) onLastPositionReached.onReached();
}
}
});
}
Update
According to your requirement, here is NestedScrollView bottom reach listener.
nestedScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
if (nestedScrollView != null) {
if (nestedScrollView.getChildAt(0).getBottom() <= (nestedScrollView.getHeight() + nestedScrollView.getScrollY())) {
//scroll view is at bottom
} else {
//scroll view is not at bottom
}
}
}
});
Thanks to Khemraj who give the tip for solution
because I have a recyclerview inside NestedScrollView and coordinator layout as parent for them
I have solved my problem like this:
public Disposable observeNestedScroll(LoadMoreListener listener) {
return RxNestedScrollView.scrollChangeEvents(nestedScrollView)
.subscribe(
viewScrollChangeEvent -> {
NestedScrollView nestedScrollView =(NestedScrollView) viewScrollChangeEvent.view();
if(nestedScrollView.getChildAt(nestedScrollView.getChildCount() - 1) != null) {
if ((viewScrollChangeEvent.scrollY() >= (nestedScrollView.getChildAt(nestedScrollView.getChildCount() - 1).getMeasuredHeight() - nestedScrollView.getMeasuredHeight())) &&
viewScrollChangeEvent.scrollY() > viewScrollChangeEvent.oldScrollY()) {
listener.onLoadMore();
}
}
});
}
I've seen to many responses for this question and I stand that all of them don't give accurate behavior as an outcome. However if you follow this approach I'm positive you'll get the best behavior.
rvCategories is your RecyclerView
categoriesList is the list passed to your adapter
binding.rvCategories.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val position = (recyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition()
if (position + 1 == categoriesList.size) {
// END OF RECYCLERVIEW IS REACHED
} else {
// END OF RECYCLERVIEW IS NOT REACHED
}
}
})
Basically I want my recyclerview to automatically scroll to a position where the item is not half shown. Like the one in googleplay.
I have written a code
public void scrollToVisible(){
int firstVisibleItemPosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
View view = recyclerView.getLayoutManager().getChildAt(0);
if (firstVisibleItemPosition > 0 && view != null) {
int offsetTop = view.getTop();
if (firstVisibleItemPosition - 1 >= 0 && adapter.getItemCount() > 0) {
((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(firstVisibleItemPosition - 1, offsetTop);
}
}
}
The problem comes next. I dont know where to put this code. I have a vague idea to put it when the recyclerview stops on scrolling but I've been searching for quite some time now and i cant find such a method. when i put it on the onScroll some unexpected behavior comes out
You may create a CustomRecyclerView extending RecyclerView
public class CustomRecyclerView extends RecyclerView {
#Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
// check if scrolling has stopped
if (state == SCROLL_STATE_IDLE) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();
// use code here
}
}
If it maybe of any help to someone:
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Log.d("y value",String.valueOf(dy));
if (dy > 0) {
//scrolling up
} else {
// Scrolling down
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
// Do something
Log.e("SCROLL_STATE_FLING","SCROLL_STATE_FLING");
} else if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
Log.e("SCROLLTOUCH_SCROLL","SCROLL_STATE_TOUCH_SCROLL");
//slideUp(party_view);
// Do something
} else if (newState==AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
// Do something
//slideDown(party_view);
Log.e("SCROLL_STATE_IDLE","SCROLL_STATE_IDLE");
}
}
});
complete example with UI synchronization
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
Handler handler = new Handler(getMainLooper());
if (newState == 0) {
handler.removeCallbacks(MainActivity.this::hideFab);
handler.postDelayed(MainActivity.this::showFab, 400);
} else {
handler.removeCallbacks(MainActivity.this::showFab);
handler.postDelayed(MainActivity.this::hideFab, 100);
}
}
});
private void hideFab() {
addFile.hide();
addText.hide();
camera.hide();
}
private void showFab() {
addFile.show();
addText.show();
camera.show();
}
I have a requirement to scroll Recyclerview in one page increments. Each page containing a grid of 3 by 3 items.
I have used GridLayoutManager to implement the grid, now I am trying to override the onScrolled() method to implement scroll by page. I want each horizontal scroll to display 3 items which represents 1 page.
Here is portion of my code
recyclerView = (RecyclerView) rootView.findViewById(R.id.sub_category_list_recyclerview);
recyclerView.setHasFixedSize(true);
gridLayoutManager = new GridLayoutManager(getContext(), rowCount, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(gridLayoutManager);
adapter = new SubCategoryGridLayoutAdapter(new ArrayList<SubCategoryViewItem>());
recyclerView.setAdapter(adapter);
recyclerView.addOnScrollListener(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) {
int visibleItemCount = gridLayoutManager.getChildCount();
int totalItemCount = gridLayoutManager.getItemCount();
int pastVisiblesItems = gridLayoutManager.findFirstVisibleItemPosition();
int lastitemPos = gridLayoutManager.findLastVisibleItemPosition();
if (dx > 0) {
//Right Scrolling
int moreItems = lastitemPos + 9;
if (totalItemCount > moreItems){
gridLayoutManager.scrollToPositionWithOffset(moreItems, 0);
}else {
gridLayoutManager.scrollToPositionWithOffset(totalItemCount, 0);
}
}
if (dx < 0) {
//Left Scrolling
int lessItems = pastVisiblesItems + 9;
if (lessItems < totalItemCount){
gridLayoutManager.scrollToPositionWithOffset(lessItems, 0);
}else {
gridLayoutManager.scrollToPositionWithOffset(totalItemCount, 0);
};
}
}
});
For future reading of this question, in support library 25.1.0 was added PageSnapHelper (for simulation of ViewPager - only scrolling item by item) or LinearSnapHelper (moves to the item that is closest to the middle of RecycleView).
Usage is simple :
PagerSnapHelper().attachToRecyclerView(rvYourRecycleViewName)
I tried implementing addOnScrollListener() but this thing fetch data and loading the recycler view from the beginning every time.i want to load the data after the current position.Here is my sample code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_load, null);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
progressBar.setVisibility(View.VISIBLE);
myClickHandler();
business_rv = (RecyclerView) view.findViewById(R.id.business_rv);
business = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL,false);
business_rv.setHasFixedSize(true);
business_rv.setLayoutManager(business);
if (business_rv.getLayoutManager() instanceof LinearLayoutManager) {
business = (LinearLayoutManager) business_rv.getLayoutManager();
business_rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
UpdateRecyclerView(url);
}
});
}
return view;
}
what you need is endless recycler view ,which will load the data while scrolling . Here I have attached link for that implementation.
Follow this link
use this as
_recycler.addOnScrollListener(_recyclerViewOnScrollListener);
private RecyclerView.OnScrollListener recyclerViewOnScrollListener = 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);
int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
if (!isLoading && !isLastPage) {
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
&& firstVisibleItemPosition >= 0
&& totalItemCount >= PAGE_SIZE) {
loadMoreItems(++currentPage);
}
}
}
};