RecyclerView控件问世已经有很长的一段时间了,想必很多人对它的基本用法很熟悉了,再此就不赘述。它可以完美的替代ListView与GridView,纵向横向皆可,瀑布流也能搞定!这么多功能,只要这一个控件就可实现,想想都心动。个人而言,用起来的话还是稍显繁琐一些,所以自己动手打造一个熟悉完美的控件。
1.布局管理器:LayoutManger
要用RecyclerView显示内容,LayoutManger是必不可少的,里面的方法setLayoutManger就是设置这个玩意的,但是对于可能一个不是很熟悉的控件,往往总会有遗漏的地方。在我们以往的ListView或者是GridView中,都没有设置过这个东西,所以咱就想了,可不可以重新继承RecyclerView自己打造一个类似Listview的控件,可以省去不必要的麻烦呢。
RecyclerView在调用方法setLayoutManger的时候已经获取到自己的实例,即不为null,
所以BaseRecycleView继承RecyclerView的时候在onFinishInflate中设置布局管理器,
这里我抽象出一个方法setFinalLayoutManger,可以根据需求自己定义。
public abstract void setFinalLayoutManger();
<span style="font-size:18px;"><span style="white-space:pre"> </span>@Override protected void onFinishInflate() { super.onFinishInflate(); setFinalLayoutManger(); addItemDecoration(new DividerItemDecoration(getContext())); }</span>
2.没有点击和长按事件,自己动手设置呗
(1)定义点击和长按事件接口
<span style="font-size:18px;"><span style="white-space:pre"> </span>//点击事件监听接口 public interface OnItemClickListener{ void onItemClick(View itemView,int position); }</span>
<span style="font-size:18px;"><span style="white-space:pre"></span><pre name="code" class="java"><span style="white-space:pre"> </span>//长按事件监听接口 public interface OnLongItemClickListener{ void onLongItemClick(View itemView,int position); }</span>
(2)对外开放设置监听事件的方法,当你在用的时候到底是先设置监听呢还是先设置adpter,不同的人有不同的习惯,所以我在此做了以下处理。
<span style="font-size:18px;"><span style="white-space:pre"> </span>public void setAdapter(Adapter adapter) { super.setAdapter(adapter); if(adapter instanceof BaseRecyleAdapter){ BaseRecyleAdapter brAdapter = (BaseRecyleAdapter) adapter; if(mListener != null){ brAdapter.setOnItemClickListener(mListener); } if(mLongListener != null){ brAdapter.setOnLongItemClickListener(mLongListener); } } } /** *设置行点击事件 */ public void setOnItemClickListener(OnItemClickListener listener){ this.mListener = listener; @SuppressWarnings("rawtypes") BaseRecyleAdapter adapter = cast(); adapter.setOnItemClickListener(mListener); } /** *设置行长按事件 */ public void setOnLongClickListener(OnLongItemClickListener listener){ this.mLongListener = listener; @SuppressWarnings("rawtypes") BaseRecyleAdapter adapter = cast(); adapter.setOnLongItemClickListener(mLongListener); } /** *获取继承自BaseRecyleAdapter的adapter */ @SuppressWarnings("rawtypes") private BaseRecyleAdapter cast(){ Adapter adapter = getAdapter(); if(adapter != null){ if(adapter instanceof BaseRecyleAdapter){ BaseRecyleAdapter brAdapter = (BaseRecyleAdapter) adapter; return brAdapter; }else{ throw new ClassCastException("getAdapter() from recyclerView can not cast BaseRecyleAdapter," + "so userd adapter should extends BaseRecyleAdapter"); } } return null; }</span>
在设置adapter的时候,会判断监听事件是否已经设置,如果设置了,就调用BaseRecycleAdapter中的设置监听事件的方法(BaseRecycleAdapter也是重写,后续会列出);在设置监听事件的时候,会判断adapter是否已经设置,如果设置了,就调用BaseRecycleAdapter中的设置监听事件的方法。重复以下,设置的adapter必须继承自BaseRecycleAdapter。
基本的BaseRecycleView已经基本竣工了,接下来就是实现自己需要的FinalRecycleView的重构了
3.打造自己满意的FinalRecycleView(继承自BaseRecycleView)
(1)这个FinalRecycleView是一个多样化的RecycleView,所以用到了自定义属性。在res/values中创建attrs.xml
<span style="font-size:18px;"><span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="FinalRecycleViewStyle"> <attr name="showStyle" format="integer"/> <!-- 显示形式,list or grid --> <attr name="spanCount" format="integer"/> <!-- grid列数 --> </declare-styleable> </resources></span></span>
(2)在res/values中创建integer.xml(用来表示attrs中showStyle的)
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?> <resources> <integer name="LISTVIEW_VERTICAL">1000</integer> <integer name="LISTVIEW_HORIZONTAL">1001</integer> <integer name="GRIDVIEW_NORMAL">1002</integer> <integer name="STAGGERED_HORIZONTAL">1003</integer> <integer name="STAGGERED_VERTICAL">1004</integer> </resources></span>
(3)属性获取,想必会自定义控件的这个都难不倒你们,就不在赘述了。
(4)最关键的方法到了,setFinalLayoutManger,这个就是我们在BaseRecyleView中抽象方法,setlayoutManger就在这里面进行设置了。
<span style="font-size:18px;"> if(showStyle == res.getInteger(R.integer.LISTVIEW_VERTICAL)){ <span style="white-space:pre"> </span>setLayoutManager(new LinearLayoutManager(mContext)); }else if(showStyle == res.getInteger(R.integer.LISTVIEW_HORIZONTAL)){ setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false)); }else if(showStyle == res.getInteger(R.integer.GRIDVIEW_NORMAL)){ setLayoutManager(new GridLayoutManager(mContext, spanCount)); }else if(showStyle == res.getInteger(R.integer.STAGGERED_HORIZONTAL)){ setLayoutManager(new StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.HORIZONTAL)); }else if(showStyle == res.getInteger(R.integer.STAGGERED_VERTICAL)){ setLayoutManager(new StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL)); }</span>
根据自己设置的不同showStyle来设置不同的布局管理器,很简单的,不说了好吗?!
4.FinalRecycleView打造完成,接下来就是FinalViewHolder,这个很简单,直接继承RecyclerView.ViewHolder代码如下:
<span style="font-size:18px;">package com.dandy.recycleview; import android.support.v7.widget.RecyclerView; import android.util.SparseArray; import android.view.View; import android.widget.TextView; public class FinalViewHolder extends RecyclerView.ViewHolder{ private View mConvertView; private SparseArray<View> mViews; public FinalViewHolder(View view) { super(view); this.mConvertView = view; this.mViews = new SparseArray<View>(); } /** * 通过控件的Id获取对于的控件,如果没有则加入views * @param viewId * @return */ @SuppressWarnings("unchecked") public <T extends View> T getView(int viewId) { View view = mViews.get(viewId); if (view == null) { view = mConvertView.findViewById(viewId); mViews.put(viewId, view); } return (T) view; } /** * 为TextView设置字符串 * @param viewId * @param text * @param visible * @return */ public void setText(int viewId, String text) { TextView view = getView(viewId); if(view != null && text != null){ view.setText(text); } } public View getContentView(){ return mConvertView; } } </span>
(5)最后就是我们的BaseRecyleAdapter的打造,重写onCreateViewHolder与onBindViewHolder方法,并且在
onBindViewHolder方法中设置监听事件,这部分比较简单,代码如下:
<span style="font-size:18px;">package com.dandy.recycleview; import java.util.List; import com.dandy.recycleview.BaseRecycleView.OnItemClickListener; import com.dandy.recycleview.BaseRecycleView.OnLongItemClickListener; import android.content.Context; import android.support.v7.widget.RecyclerView.Adapter; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.View.OnClickListener; public abstract class BaseRecyleAdapter <T> extends Adapter<FinalViewHolder>{ public OnItemClickListener mListener; public OnLongItemClickListener mLongListener; public Context mContext; public List<T> mDatas; public int itemLayoutId; public BaseRecyleAdapter(Context context,List<T> datas,int itemLayoutId) { this.mContext = context; this.mDatas = datas; this.itemLayoutId = itemLayoutId; } @Override public int getItemCount() { if(mDatas != null){ return mDatas.size(); } return 0; } @Override public FinalViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) { View view = LayoutInflater.from(mContext).inflate(itemLayoutId,viewGroup,false); return new FinalViewHolder(view); } @Override public void onBindViewHolder(FinalViewHolder viewHolder, final int position) { viewHolder.getContentView().setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(mListener != null){ mListener.onItemClick(v, position); } } }); viewHolder.getContentView().setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { if(mLongListener != null){ mLongListener.onLongItemClick(v, position); return true; } return false; } }); convertBindViewHolder(viewHolder,position); } public abstract void convertBindViewHolder(FinalViewHolder viewHolder, final int position); public void setOnItemClickListener(OnItemClickListener listener){ this.mListener = listener; } public void setOnLongItemClickListener(OnLongItemClickListener listener){ this.mLongListener = listener; } } </span>
(6)自己满意的RecyleView打造完成了,效果如何呢,上图不解释
版权声明:本文为博主原创文章,未经博主允许不得转载。