天天看点

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还在完善中,后续会发出来。 

继续阅读