說明:如下代碼中的註釋只是爲了說明,在實際當中是不須要的。緩存
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的間距還須要從新寫,可是可支配程度也提升了,能夠說有利有弊。