说明:如下代码中的注释只是为了说明,在实际当中是不须要的。缓存
RecyclerView的这个控件的出现简直是很是方便平常开发,我以为能够直接替代listview和gridview了,而且用来写瀑布流是很是方便的。异步
其实对于RecyclerView的使用区别其排列方式的是布局管理器,分别为:ide
LinearLayoutManager:线性布局管理器布局
StaggeredGridLayoutManager: 错列网格布局管理器(瀑布流的一种方式)this
GridLayoutManager:网格布局管理器spa
首先介绍一下瀑布流的方式: code
从上图中能够看出,每个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里面了。ip
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的间距还须要从新写,可是可支配程度也提升了,能够说有利有弊。