使用 staggeredGridLayoutManager 和 recyclerView 进行分页

Posted

技术标签:

【中文标题】使用 staggeredGridLayoutManager 和 recyclerView 进行分页【英文标题】:Pagination with staggeredGridLayoutManager and recyclerView 【发布时间】:2018-12-21 19:19:50 【问题描述】:

您好,我需要使用 staggeredGridLayoutManager 使用 recyclerview 进行无限滚动(分页)。分页正在工作,但问题是 onLoadMore() 函数在滚动时被调用了很多次导致问题,这是我的代码:

 newSearchAdapter = new NewSearchAdapter(getActivity(), gridData);
            StaggeredGridLayoutManager mLayoutManager;
            mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
            mLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
            rv_NewProfilesGrid.setLayoutManager(mLayoutManager);
            rv_NewProfilesGrid.setAdapter(newSearchAdapter);
            rv_NewProfilesGrid.addOnScrollListener(new EndlessRecyclerOnScrollListenerStaggeredLayoutmanager(mLayoutManager) 
                @Override
                public void onLoadMore(int current_page) 

                  //calling the api

                
            );

这是我的滚动监听器

我认为这里的问题在于 getFirstVisibleItems() 函数,因为使用 GridLayoutMangerLinearLayoutManager 它返回一个整数,但使用 StaggeredLayout 它返回一个 int 数组,所以我做了以下操作:

public abstract class EndlessRecyclerOnScrollListenerStaggeredLayoutmanager extends RecyclerView.OnScrollListener 
    public static String TAG = EndlessRecyclerOnScrollListenerStaggeredLayoutmanager.class.getSimpleName();
    private int scrolledDistance = 0;
    private boolean controlsVisible = false;

    private boolean loading = true; // True if we are still waiting for the last set of data to load.
    private int visibleThreshold = 5; // The minimum amount of items to have below your current scroll position before loading more.
    public static boolean  loadOneTime = false;
    private int pastVisibleItems, visibleItemCount, totalItemCount,previousTotal;

    private int current_page = 1;

    private StaggeredGridLayoutManager mStaggeredGridLayoutManager;

    public EndlessRecyclerOnScrollListenerStaggeredLayoutmanager(StaggeredGridLayoutManager staggeredGridLayoutManager) 
        this.mStaggeredGridLayoutManager = staggeredGridLayoutManager;

    


    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) 
        super.onScrolled(recyclerView, dx, dy);

        visibleItemCount = recyclerView.getChildCount();
        totalItemCount = mStaggeredGridLayoutManager.getItemCount();

        int[] firstVisibleItems = null;
        firstVisibleItems = mStaggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);
        if (firstVisibleItems != null && firstVisibleItems.length > 0) 
            pastVisibleItems = firstVisibleItems[0];
        


        if (loading) 
            if ((visibleItemCount + pastVisibleItems) >= totalItemCount) 
                loading = false;

                previousTotal = totalItemCount;
            
        
        if (!loading && (totalItemCount - visibleItemCount)
                <= (pastVisibleItems + visibleThreshold)) 
            // End has been reached

            // Do something
            current_page++;
            loadOneTime=false;
            onLoadMore(current_page);

            loading = true;
        

        if (scrolledDistance > 1 && controlsVisible) 
            controlsVisible = false;
            scrolledDistance = 0;
         else if (scrolledDistance < -1 && !controlsVisible) 
            controlsVisible = true;
            scrolledDistance = 0;
        

        if ((controlsVisible && dy > 0) || (!controlsVisible && dy < 0)) 
            scrolledDistance += dy;
        
    

    public abstract void onLoadMore(int current_page);



【问题讨论】:

我遇到了同样的问题,但是使用了 Paging 库并遇到了这个 github gist gist.github.com/pratikbutani/dc6b963aa12200b3ad88aecd0d103872 我认为它会解决你的问题 【参考方案1】:

试试这个。我从堆栈溢出答案中借用它并借用另一个答案并结合它们我终于解决了它。

import android.util.Log
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager

abstract class PaginationScrollListener constructor() :
    RecyclerView.OnScrollListener() 

    private lateinit var mLayoutManager: RecyclerView.LayoutManager

    constructor(layoutManager: GridLayoutManager) : this() 
        this.mLayoutManager = layoutManager
    

    constructor(layoutManager: StaggeredGridLayoutManager) : this() 
        this.mLayoutManager = layoutManager
    

    constructor(layoutManager: LinearLayoutManager) : this() 
        this.mLayoutManager = layoutManager
    


    /*
     Method gets callback when user scroll the search list
     */
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) 
        super.onScrolled(recyclerView, dx, dy)

        val visibleItemCount = mLayoutManager.childCount
        val totalItemCount = mLayoutManager.itemCount
        var firstVisibleItemPosition = 0

        when (mLayoutManager) 
            is StaggeredGridLayoutManager -> 
                val firstVisibleItemPositions =
                    (mLayoutManager as StaggeredGridLayoutManager).findFirstVisibleItemPositions(null)
                // get maximum element within the list
                firstVisibleItemPosition = firstVisibleItemPositions[0]
            
            is GridLayoutManager -> 
                firstVisibleItemPosition =
                    (mLayoutManager as GridLayoutManager).findFirstVisibleItemPosition()
            
            is LinearLayoutManager -> 
                firstVisibleItemPosition =
                    (mLayoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
            
        
        if (!isLoading && !isLastPage) 
            if (visibleItemCount + firstVisibleItemPosition >= totalItemCount
                && firstVisibleItemPosition >= 0
            ) 
                Log.i(TAG, "Loading more items")
                loadMoreItems()
            
        
    

    protected abstract fun loadMoreItems()

    abstract val isLastPage: Boolean
    abstract val isLoading: Boolean

    companion object 
        private val TAG = PaginationScrollListener::class.java.simpleName
    

并以这种方式在您的回收站视图中使用它

rvCategoryProducts.addOnScrollListener(object :
            PaginationScrollListener(layoutManager) 
            override fun loadMoreItems() 
                vm.isLoading = true
                vm.currentPage++

                GlobalScope.launch 
                    vm.getCategoryProductByCatId(vm.id, vm.currentPage)
                
            

            override val isLastPage: Boolean
                get() = vm.isLastPage
            override val isLoading: Boolean
                get() = vm.isLoading
        )

【讨论】:

以上是关于使用 staggeredGridLayoutManager 和 recyclerView 进行分页的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)