说明:以下代码中的注释只是为了说明,在实际当中是不需要的。
RecyclerView的这个控件的出现简直是非常方便日常开发,我觉得可以直接替代listview和gridview了,并且用来写瀑布流是非常方便的。
其实对于RecyclerView的使用区别其排列方式的是布局管理器,分别为:
LinearLayoutManager:线性布局管理器
StaggeredGridLayoutManager: 错列网格布局管理器(瀑布流的一种方式)
GridLayoutManager:网格布局管理器
首先介绍一下瀑布流的方式:
从上图中可以看出,每一个item中包含了图片和文字的,图片是异步加载的,那么问题就来了,如果按照常规流程写完代码之后,在滑动时图片会出现各种各样的问题,比如滑动闪烁、图片错位、顶位图片移动。通过查找解决问题代码如下:
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
//RecyclerView滑动过程中不断请求layout的Request,不断调整item见的间隙,并且是在item尺寸显示前预处理,因此解决RecyclerView滑动到顶部时仍会出现移动问题
layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
RecyclerView scene_recyclerview = (RecyclerView) view.findViewById(R.id.scene_recyclerview);
scene_recyclerview.addItemDecoration(new RecycleViewItemDecoration(20));
scene_recyclerview.setLayoutManager(layoutManager);
scene_recyclerview.setItemViewCacheSize(0);//去掉缓存
findSceneList = new ArrayList<>()
SceneRecyclerViewAdapter recyclerViewAdapter = new SceneRecyclerViewAdapter(getContext(), findSceneList);
scene_recyclerview.setAdapter(recyclerViewAdapter);
scene_recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// 网上说的这种方式是没有效果的,所以注释不用
// layoutManager.invalidateSpanAssignments();//避免顶部出现空白区域,其实就是重新绘制了一遍
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
/**
*通过下面的方式,判断是否滑动到顶部还是滑动到底部的监听
*/
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager();
int[] firstVisibleItem = null;
firstVisibleItem = staggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItem);
if (firstVisibleItem != null && (firstVisibleItem[0] == 0 || firstVisibleItem[0] == 1)) {
//表明此时滑动到顶部了
}
int[] lastVisibleItem = null;
lastVisibleItem = staggeredGridLayoutManager.findLastVisibleItemPositions(lastVisibleItem);
if (lastVisibleItem != null && (lastVisibleItem[0] == findSceneList.size() || lastVisibleItem[0] == findSceneList.size() - 1)
&& (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange())) {//这种方式表明只有滑动到已有数据的最底部才开始加载数据
//表明此时滑动到底部了
pageIndex++;
getSceneList();
}
// if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()) {
// //这种方式会造成第一次打开所有场景页面数据请求两遍
// //滑动到底部
// pageIndex++;
// getSceneList();
// }
}
});
RecycleViewItemDecoration这个类是用来调整瀑布流的item的间距的。
/**
* RecyclerView的item的间距
* 设置为2列,如果是3列或者其它列,那么左右值不同
*/
public class RecycleViewItemDecoration extends RecyclerView.ItemDecoration {
private int space = 0;
private int pos;
public RecycleViewItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
pos = parent.getChildAdapterPosition(view);//该View在整个RecyclerView中的位置
if (parent.getChildAdapterPosition(view) == 0 || parent.getChildAdapterPosition(view) == 1) {
outRect.top = space;
}
outRect.bottom = space;
outRect.left = space;
outRect.right = space;
//两列的左边一列
// if (pos % 2 == 0) {
// outRect.left = space;
// outRect.right = space/2;
// }
// //两列的右边一列
// if (pos % 2 == 1) {
// outRect.left = space/2;
// outRect.right = space/10;
// }
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
c.drawColor(ContextCompat.getColor(parent.getContext(), R.color.base_bg_color));//绘制item间隔的颜色
}
}
监听item图片的点击事件是放在适配器SceneRecyclerViewAdapter里面了。
public class SceneRecyclerViewAdapter extends RecyclerView.Adapter<SceneRecyclerViewAdapter.MyViewHolder> {
private Context context;
private ArrayList<FindSceneBean> findSceneList;//数据源
private ImageLoad imageLoad;
private int itemWidth;
public SceneRecyclerViewAdapter(Context context, ArrayList<FindSceneBean> findSceneList) {
this.context = context;
this.findSceneList = findSceneList;
imageLoad = new ImageLoad(context);
itemWidth = (Util.getScreenWidth(context) - 62)/2;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.scene_recyclerview_item, null);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
//这里是重新设置一下图片的宽度,
holder.goodsImage.measure(0, 0);
// double ratio = (itemWidth * 1.0)/holder.goodsImage.getMeasuredWidth();
ViewGroup.LayoutParams params = holder.goodsImage.getLayoutParams();
params.width = itemWidth;
// params.height = (int) (holder.goodsImage.getMeasuredHeight() * ratio);
holder.goodsImage.setLayoutParams(params);
//这里要先添加一下默认图片
holder.goodsImage.setImageDrawable(context.getDrawable(R.drawable.home_page_vice_pic));
if (!Util.isTextNull(findSceneList.get(position).OrginImageUrl)) {
imageLoad.loadImage(holder.goodsImage, findSceneList.get(position).OrginImageUrl);
}
holder.title.setText(findSceneList.get(position).Description);
holder.falNumTv.setText(findSceneList.get(position).LikeNum + "");
final FindSceneBean findSceneBean = findSceneList.get(position);
if (findSceneBean != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//点击监听
}
});
}
}
@Override
public int getItemViewType(int position) {
return position;
}
@Override
public int getItemCount() {
return findSceneList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView title;//标题
TextView falNumTv;//收藏数
ImageView goodsImage;//商品图片
ImageView falImage;//收藏数的图标
public MyViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.scene_item_title);
falNumTv = (TextView) itemView.findViewById(R.id.scene_item_falNumTv);
goodsImage = (ImageView) itemView.findViewById(R.id.scene_item_goodsImage);
falImage = (ImageView) itemView.findViewById(R.id.scene_item_falImage);
}
}
}
上面写的是RecyclerView用来写瀑布流的方式,接下来介绍RecyclerView用来写类似gridview的方式。
首先说明一点在写表格布局时没有出现想瀑布流中那么多图片加载的问题,所以不需要再对图片加载进行调整。
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 2);
//RecyclerView滑动过程中不断请求layout的Request,不断调整item见的间隙,并且是在item尺寸显示前预处理,因此解决RecyclerView滑动到顶部时仍会出现移动问题
// layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
commodity_gridview = (RecyclerView) view.findViewById(R.id.commodity_gridview);
commodity_gridview.addItemDecoration(new RecycleViewItemDecoration(20));
commodity_gridview.setLayoutManager(layoutManager);
commodity_gridview.setItemViewCacheSize(0);
commoGridViewRequestList = new ArrayList<>();
commoGridViewList = new ArrayList<>();
commoGridViewAdapter = new CommoGridViewAdapter(getContext(), commoGridViewList);
commodity_gridview.setAdapter(commoGridViewAdapter);
commodity_gridview.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
int firstVisibleItem = gridLayoutManager.findFirstVisibleItemPosition();
if (firstVisibleItem == 0) {
//表明此时滑动到顶部了
}
int lastVisibleItem = gridLayoutManager.findLastVisibleItemPosition();
if ((lastVisibleItem == commoGridViewList.size() - 1)
&& (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange())) {
//表明此时滑动到底部了
pageIndex++;
getGoodsList();
}
}
});
适配器CommoGridViewAdapter的代码:
public class CommoGridViewAdapter extends RecyclerView.Adapter<CommoGridViewAdapter.MyHolder> {
private Context context;
private ArrayList<CommoGridViewBean> commoGridViewList;
private ImageLoad imageLoad;
public CommoGridViewAdapter(Context context, ArrayList<CommoGridViewBean> commoGridViewList) {
this.context = context;
this.commoGridViewList = commoGridViewList;
imageLoad = new ImageLoad(context);
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.recommend_good_adapter_layout, null);
view.setBackgroundColor(ContextCompat.getColor(context, R.color.white));
MyHolder myViewHolder = new MyHolder(view);
return myViewHolder;
}
@Override
public void onBindViewHolder(final MyHolder holder, int position) {
try {
final CommoGridViewBean commoGridViewBean = commoGridViewList.get(position);
if (commoGridViewBean != null) {
if (!Util.isTextNull(commoGridViewBean.ThumbImageUrl)) {
imageLoad.loadImage(holder.desc_dispaly, commoGridViewBean.ThumbImageUrl);
}
holder.tv_name.setText(commoGridViewBean.Title);
holder.tv_price.setText(Util.getNewRMBSymbolPrice(commoGridViewBean.Price));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//点击事件
}
});
}
} catch (Exception e) {
LogUtil.e(getClass(), "onBindViewHolder", e);
}
}
@Override
public int getItemCount() {
return commoGridViewList.size();
}
@Override
public int getItemViewType(int position) {
return position;
}
class MyHolder extends RecyclerView.ViewHolder {
ImageView desc_dispaly;
TextView tv_name;
TextView tv_price;
public MyHolder(View itemView) {
super(itemView);
desc_dispaly = (ImageView) itemView.findViewById(R.id.recomm_img);
tv_name = (TextView) itemView.findViewById(R.id.recomm_title);
tv_price = (TextView) itemView.findViewById(R.id.recomm_price);
}
}
}
个人感受:RecyclerView非常方便,可以实现很好的展示效果。但是在异步加载图片时容易出问题,要具体问题具体分析。对于item的间距还需要重新写,但是可支配程度也提高了,可以说有利有弊。