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();
}
}
上个效果图吧,
demo还在完善中,后续会发出来。