天天看點

RecyclerView實作瀑布流,完美解決留白、錯亂等問題

RecyclerView實作瀑布流,完美解決留白、錯亂等問題,廢話不多說。

網上很多說解決留白要用:

layoutManager.invalidateSpanAssignments();
           

是滴 雖然留白解決了,but會出現新的問題,當你往上滑動到頂部的時候,明顯左右item其中一個必然出現向下滑動的視覺效果,很惡心的一個坑,是以說這個方法最好别用,因為隻是從一個坑跳進了另一個坑裡邊,而且這個方法會造成界面的頻繁繪制。解決方法下邊會說到。

防止錯亂,抖動方法如下:

//防止item 交換位置
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
        recyclerView.setLayoutManager(layoutManager);
        ((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
        ((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
        recyclerView.getItemAnimator().setChangeDuration(0);
        recyclerView.setHasFixedSize(true);
        recyclerView.addItemDecoration(new SpaceItemDecoration(2, 20));
           

防止留白方法如下:

RecyclerView實作瀑布流,比如要用到加載更多的方法,解決辦法就在這裡,加載更多的時候,資料填充進adapter之後的重新整理,要用這個方法

notifyItemRangeInserted(positon,size);
1:其中position就是你添加資料之前,adapter裡邊的資料總量,其實也是開始重新整理的那個下标的位置
2:size就是加載更多擷取到的第二頁的資料的長度
3:用這個方法之前,要先把擷取到的資料通過addAll()方法先注入到adapter的資料集合中,之後可以調用這個方法

類似這樣:
  preDataNum = this.data.size();
  this.data.addAll(data);
  notifyItemRangeInserted(preDataNum,data.size());

另:
   notifyItemInserted(preDataNum);
   notifyItemRangeChanged(preDataNum,data.size());
   notifyDataSetChanged();
   notifyItemRangeInserted(preDataNum,data.size());
   notifyItemChanged(preDataNum -1);
  雖然提供的局部重新整理的防範很多,但是在這裡,親測 隻有notifyItemRangeInserted(preDataNum,data.size());這個辦法靠譜
           

其次就是設定每個item的寬高,目前demo還在完善中,寬高的設定,目前是通過重寫imageview實作的

public class DynamicHeightImageView extends ImageView {

    private double mHeightRatio;

    public DynamicHeightImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DynamicHeightImageView(Context context) {
        super(context);
    }

    public void setHeightRatio(double ratio) {
        if (ratio != mHeightRatio) {
            mHeightRatio = ratio;
            requestLayout();
        }
    }

    public double getHeightRatio() {
        return mHeightRatio;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mHeightRatio > 0.0) {
            // set the image views size
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = (int) (width * mHeightRatio);
            setMeasuredDimension(width, height);
        }
        else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}
           

因為這裡我給每個item的寬度設定的match_parent,瀑布流是兩列的,這裡我隻用設定每個item的比率就行了。

使用方法:

在onBindViewHolder中設定 
 holder.image.setHeightRatio(ratio);//設定高寬比
           

多加點吧,RecyclerView實作加載更多,重寫RecyclerView

public class StaggerRecyclerView extends RecyclerView {

    private OnLoadMoreListener onLoadMoreListener;
    private boolean isLoadingMore = false;
    private static final int TOLAST = 2;

    public StaggerRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.addOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                StaggeredGridLayoutManager layoutManager = null ;
                if(recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager){
                    layoutManager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager();
                }else{
                    return;
                }
                //下面這句話,就是上邊提到的,不能用
                //layoutManager.invalidateSpanAssignments();
                int[] positions = null;
                int[] into = layoutManager.findLastCompletelyVisibleItemPositions(positions);
                int[] firstInto = layoutManager.findFirstVisibleItemPositions(positions);
                int lastPositon = Math.max(into[0],into[1]);
                int firstPositon = Math.max(firstInto[0],firstInto[1]);

                if(!isLoadingMore && dy>0 && layoutManager.getItemCount()-lastPositon<=TOLAST){
                    //load more
                    isLoadingMore = true;
                    if(onLoadMoreListener!=null){
                        onLoadMoreListener.onLoadMore();
                    }

                }
            }
        });
    }

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
        this.onLoadMoreListener = onLoadMoreListener;
    }

    public void setLoadingMoreComplete(){
        isLoadingMore = false;
    }

    public  interface OnLoadMoreListener{
        void onLoadMore();
    }


}
           

上個效果圖吧,

RecyclerView實作瀑布流,完美解決留白、錯亂等問題

demo還在完善中,後續會發出來。 

繼續閱讀