Search code examples
androidandroid-recyclerviewandroid-viewrecyclerview-layoutgridlayoutmanager

Load more than 10 items in RecyclerView with GridLayoutManager of 3 span count on first time


I using GridLayoutManager with 3 span count in recyclerView on my app, the problem is when I run the app first time it's showing only first 10 items due to the the restriction / pagiation of the items from server, when user refreshing with SwipeRefreshLayout or scrolling it's continue loading other items, but it's look ugly on first load of items so I want fill these gaps without necessary for refreshing to load other items

here's the gridlayout with scroll listener

gridLayoutManager = new GridLayoutManager(MainActivity.this, 3);

 recyclerView.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;
                    progressBar.setVisibility(View.GONE);

                }

            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dy > 0) {
                        currentItems = gridLayoutManager.getChildCount();
                        totalItems = gridLayoutManager.getItemCount();
                        scrollOutItems = gridLayoutManager.findFirstVisibleItemPosition();

                    if (isScrolling && (currentItems + scrollOutItems == totalItems)) {
                        isScrolling = false;
                        if (getItemsByLabelCalled) {
                            for (int i = 1; i < 7; i++) {
                                if (navigationView.getMenu().getItem(i).isChecked()) {
                                    getItemsByLabel(navigationView.getMenu().getItem(i).getTitle().toString());
                                }
                            }
                        } else {
                            getData();
                        }
                    }
                }
            }
        });

SwipeRefreshLayout

swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                if (navigationView.getMenu().getItem(0).isChecked()) {
                    if (Utils.hasNetworkAccess(MainActivity.this)) {
                        getData();
                    } else {
                        Toast.makeText
                                (MainActivity.this, R.string.SwipeRefreshLayout_connect_to_update
                                        , Toast.LENGTH_LONG).show();
                    }
                } else {
                    for (int i = 1; i < 7; i++) {
                        if (navigationView.getMenu().getItem(i).isChecked()) {
                            getItemsByLabel(navigationView.getMenu().getItem(i).getTitle().toString());
                        }
                    }
                }

                new Handler().postDelayed(() -> swipeRefreshLayout.setRefreshing(false), 2000);
            }

        });

The problem described with images


Solution

  • The problem is that your items count is not enough to fill the entire page. There are two ways to overcome this issue.

    1. You can call your getData method one more time after loading the first batch to get more data which is not a clean solution since you might need more items on larger screens like tablets.

    2. Put your load more procedure in onBindViewHolder method of your recycler view adapter instead of its on scroll listener. You can do the load more if position == getItemCount()-1 for instance which requests server for more items if your last item gets in view (or needs binding). Remember that you have to hold a boolean in order to prevent repetitive calls on your getData.