I'm trying to develop a recyclerview, that needs to load new elements, as the user scrolls down (a recycler for news feed). The problem is that with any method I try, my adapter sees that the visible items from recycler are same as getItemCount. One method I tried was override following class in adapter:
#Override
public void onViewAttachedToWindow(#NonNull ViewHolder holder) {
super.onViewAttachedToWindow(holder);
if((getItemCount() -1) == holder.getAdapterPosition()){
Log.e("TAGNews", "List Done!");
}
}
or, another mehthod implemented in my fragment:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = manager.getChildCount();
int totalItemCount = manager.getItemCount();
int firstVisibleItem = manager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
Log.e("News!", "end called");
loadMoreNews();
loading = true;
}
}
});
But always, my messages for debug, that must trigger by the end of the recycler, are triggered when recycler opens.
Here's how my recycler looks for the first time it's opened, without any scrolling
I load from 3 to 10 items from my backend and news have similar height.
Thanks in advice!
Please change your second code to this:
int lastCompletelyVisibleItemPosition;
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastCompletelyVisibleItemPosition = ((LinearLayoutManager) binding.recycler.getLayoutManager()).findLastVisibleItemPosition();
if (dy > 5)
if (lastCompletelyVisibleItemPosition == models.size() - 1) {
loadMoreData();
}
}
});
Related
I have followed this tutorial on how to achieve pagination with Firestore, however I need to use it with combined queries so I customized my code to look like this:
//combining queries
ArrayList<Task> tasks = new ArrayList<>();
for (String user : following) {
Task t = postRef.whereEqualTo("publisher", user).orderBy("Date", Query.Direction.DESCENDING).limit(1).get();
tasks.add(t);
}
//getting the result from combined queries - works fine
Task<List<QuerySnapshot>> allTasks = Tasks.whenAllSuccess(tasks);
allTasks.addOnSuccessListener(new OnSuccessListener<List<QuerySnapshot>>() {
#Override
public void onSuccess(List<QuerySnapshot> querySnapshots) {
for (QuerySnapshot queryDocumentSnapshots : querySnapshots) {
for (QueryDocumentSnapshot document : queryDocumentSnapshots) {
PostModel post = document.toObject(PostModel.class);
PostsDataHolder.add(post);
}
progressBar.setVisibility(View.GONE);
recyclerView.setVisibility(VISIBLE);
if (queryDocumentSnapshots.size()>0)lastVisible = queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1);
}
buildRecyclerView();
Toast.makeText(getActivity() , PostsDataHolder.size()+"", Toast.LENGTH_SHORT).show();
RecyclerView.OnScrollListener onScrollListener = 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);
int firstVisibileItem = linearLayoutManager.findFirstVisibleItemPosition();
int visibleItemCount = linearLayoutManager.getChildCount();
int totalItemCount = linearLayoutManager.getItemCount();
if (isScrolling && (firstVisibileItem + visibleItemCount == totalItemCount) && !isLastItemPaged) {
isScrolling = false;
// getting the next queries
ArrayList<Task> nextTasks = new ArrayList<>();
for (String user : following) {
Task t = postRef.whereEqualTo("publisher", user).orderBy("Date").startAfter(lastVisible).limit(1).get();
nextTasks.add(t);
}
//getting the next results - doesn't work i just get the same results as the first query
Task<List<QuerySnapshot>> nextAllTasks = Tasks.whenAllSuccess(tasks);
nextAllTasks.addOnSuccessListener(new OnSuccessListener<List<QuerySnapshot>>() {
#Override
public void onSuccess(List<QuerySnapshot> querySnapshots) {
for (QuerySnapshot nextQueryDocumentSnapshots : querySnapshots)
{
for (QueryDocumentSnapshot document : nextQueryDocumentSnapshots) {
PostModel post = document.toObject(PostModel.class);
PostsDataHolder.add(post);
}
adapter.notifyDataSetChanged();
if (nextQueryDocumentSnapshots.size() < 1) isLastItemPaged = true;
if (nextQueryDocumentSnapshots.size() > 0)
lastVisible = nextQueryDocumentSnapshots.getDocuments().get(nextQueryDocumentSnapshots.size() - 1);
}
}
});
}
}
};
recyclerView.addOnScrollListener(onScrollListener);
}
});
But the posts are just duplicating instead of getting new ones, I have read somewhere in the documentation about continueWith() but I don't seem to understand how it works, is that what I'm missing in my code?
It's not possible to exclude documents from a query. To that point, if you if you are performing multiple queries (for any reason), it's not possible to have them return only unique documents among those queries.
To put it another way: each query will always return all of the matching document, regardless of any other conditions you might like to impose. You will have to remove any duplicate documents from your result sets in the code that performs the queries. There is no alternative or workaround for this.
I have an app which have a recycler with product and anothe layout above with categories
I want to expand and collapse the categories when the recycler scroll like this video
I made a class that listens to scroll:
public abstract class MyRecyclerScroll extends RecyclerView.OnScrollListener {
final float MINIMUM = 200;
int scrollDist = 0;
boolean isVisible = true;
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (isVisible && scrollDist > MINIMUM) {
hide();
scrollDist = 0;
isVisible = false;
}
else if (!isVisible && scrollDist < -MINIMUM) {
show();
scrollDist = 0;
isVisible = true;
}
if ((isVisible && dy > 0) || (!isVisible && dy < 0)) {
scrollDist += dy;
}
}
public abstract void show();
public abstract void hide();
}
Then I used it on recycler.setOnScrollListener like this:
rec.setOnScrollListener(new MyRecyclerScroll() {
#Override
public void show() {
}
#Override
public void hide() {
}
});
I've seen several infinite scroll examples for recyclerview, but they are all scrolling down.
what I want is to load my list again and again but regardless of whether the user scrolls from above or below.
Normal List
Scroll Up
Scroll Down
that way show the same ready over and over again with an infinite scroll
Thanks!
it is Pagination :)
you can do it by adding a scroll listener
// Pagination
recyclerView.addOnScrollListener(recyclerViewOnScrollListener);
then
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();
}
}
}
};
read this article for more things:
medium
I am using ViewPager in one of my android application. I am learning yet Android and so does not know much about it. I want disable swipe from left to right and right to left on position based. I have searched in stackoverflow for solution but not got any proper solution. I am attaching my code here. Let me know if someone can help me to solve this puzzle.
My ViewPager
adapter = new MyAdapter(getSupportFragmentManager());
viewPager.setOffscreenPageLimit(0);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
constant.new_ad_count = constant.new_ad_count + 1;
mItemIndx = position;
try {
int index = position % ITEMS_PER_PAGE;
currentQuote = quotes.get(index);
} catch
(Exception e) {
}
mPageIndx = ((position + 1) / ITEMS_PER_PAGE) + (((position + 1) % ITEMS_PER_PAGE) > 0 ? 1 : 0);
updateUI();
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(mItemIndx);
updateUI();
}
Function From Which I want Disable Swipe
private void updateUI() {
lblLikeCount.setText(currentQuote.getQuLike());
lblShareCount.setText(currentQuote.getQuShare());
lblTime.setText(currentQuote.getQuTime());
textPageCount.setText((mItemIndx + 1) + " / " + totalSize);
// butNext.setVisibility((mItemIndx < totalSize - 1) ? View.VISIBLE : View.INVISIBLE);
butPrev.setVisibility((mItemIndx > 0) ? View.VISIBLE : View.INVISIBLE);
if(mItemIndx==totalSize-1||(mItemIndx+1)%ITEMS_PER_PAGE==0) {
butNext.setVisibility(View.INVISIBLE);
//I want Disable Right to Left Swipe Here
} else {
butNext.setVisibility(View.VISIBLE);
}
if (mItemIndx-1<0 ||(mItemIndx)%ITEMS_PER_PAGE==0) {
butPrev.setVisibility(View.INVISIBLE);
//I want Disable Left to Right Here
} else {
butPrev.setVisibility(View.VISIBLE);
}
}
Thanks a lot Friends :)
Use a this NonSwipableViewPager class, using this, you will only be able to change the page when calling setCurrentItem.
public class NonSwipeableViewPager extends ViewPager {
public NonSwipeableViewPager(Context context) {
super(context);
setMyScroller();
}
public NonSwipeableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setMyScroller();
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
//down one is added for smooth scrolling
private void setMyScroller() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
scroller.set(this, new MyScroller(getContext()));
} catch (Exception e) {
e.printStackTrace();
}
}
public class MyScroller extends Scroller {
public MyScroller(Context context) {
super(context, new DecelerateInterpolator());
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/);
}
}
Add this class to your project, then in the layout where you want it, replace ViewPager with:
<yourpackagename.NonSwipeableViewPager
Then initialise it in your Activity or Fragment:
NonSwipeableViewPager pager = (NonSwipeableViewPager) findViewById(R.id.pager);
I am using endless Recyclerview which is loading data from Parse.com database.The problem I am facing is that it is displaying two loading images like shown in below screen.I want to display one item at time and then on scrolling show the icon then load the next item.
Code for EndlessScroll is -
public abstract class EndlessScroll extends RecyclerView.OnScrollListener {
public static String TAG = EndlessScroll.class.getSimpleName();
private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = true; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 2; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;
Context context;
private int current_page = 1;
private LinearLayoutManager mLinearLayoutManager;
public EndlessScroll(LinearLayoutManager linearLayoutManager, Context context) {
this.mLinearLayoutManager = linearLayoutManager;
this.context = context;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
current_page++;
onLoadMore(current_page);
loading = true;
}
}
public abstract void onLoadMore(int current_page);
}
I have started working in android of late.
I am not sure why the loading behaviour is problematic.
Your help/suggestion/any pointer is much appreciated.