不多说 先看效果图:
-------------------------------------------------------------------------------------------------------------------------------
1.首先实现一个Model实体,该Model需要包含区分不同组的字段,例如下面这个实体用来区分的便是mTitle字段,当然这个字段是随便取什么的,只要定好就可以。
public class Model { private String mTitle; private String mContent; private int mRsId; public Model(String title, String content, int rsId) { mTitle = title; mContent = content; mRsId = rsId; } public String getTitle() { return mTitle; } public void setTitle(String title) { mTitle = title; } public String getContent() { return mContent; } public void setContent(String content) { mContent = content; } public int getRsId() { return mRsId; } public void setRsId(int rsId) { mRsId = rsId; } }
2.创建一个RecyclerView并且实现实现适配器,先实现如下效果:
3.适配器代码如下:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> { private List<Model> mModelList; private LayoutInflater mInflater; public RecyclerAdapter(Context context,List<Model> modelList) { mInflater = LayoutInflater.from(context); mModelList = modelList; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout.item_l, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(RecyclerAdapter.ViewHolder holder, int position) { Model model = mModelList.get(position); holder.mTextView.setText(model.getContent()); holder.mImageView.setImageResource(model.getRsId()); } @Override public int getItemCount() { return mModelList.size(); } class ViewHolder extends RecyclerView.ViewHolder { private TextView mTextView; private ImageView mImageView; public ViewHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(R.id.txt); mImageView = (ImageView) itemView.findViewById(R.id.img); } } }
4.接下来编写一个接口用来对数据判断:
public interface ISticky { //判断是否为同类别的第一个位置 boolean isFirstPosition(int pos); //获取标题 String getGroupTitle(int pos); }
5.最重要的一步来了 就是自定义ItemDecoration,代码如下,详细注释我已经写在里面了
public class StickyItemDecoration extends RecyclerView.ItemDecoration { private ISticky mISticky; //矩形高度 private int mRectHeight; //文字TextSize private int mTextPaintSize; private Paint mTxtPaint; private Paint mRectPaint; //分割线画笔 private Paint mDividerPaint; //手机状态栏的高度 private int mStatusBarHeight; public StickyItemDecoration(Context context, int statusBarHeight, ISticky iSticky) { mStatusBarHeight=statusBarHeight; mISticky=iSticky; mRectHeight= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,30, context.getResources().getDisplayMetrics()); mTextPaintSize=(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,17, context.getResources().getDisplayMetrics()); mTxtPaint=new Paint(Paint.ANTI_ALIAS_FLAG); mTxtPaint.setColor(Color.BLACK); mTxtPaint.setTextSize(mTextPaintSize); mRectPaint=new Paint(Paint.ANTI_ALIAS_FLAG); mRectPaint.setStyle(Paint.Style.FILL); mRectPaint.setColor(Color.parseColor("#DDDDDD")); mDividerPaint=new Paint(Paint.ANTI_ALIAS_FLAG); mDividerPaint.setStyle(Paint.Style.FILL); mDividerPaint.setColor(Color.WHITE); } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); int childCount=parent.getChildCount(); for (int i = 0; i < childCount; i++) { View view=parent.getChildAt(i); int left=parent.getPaddingLeft(); int right=parent.getWidth()-parent.getPaddingRight(); int top=view.getTop()-1; int bottom=view.getTop(); //Item分割线 c.drawRect(left,top,right,bottom,mDividerPaint); } } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); int childCount=parent.getChildCount(); int itemCount=state.getItemCount(); int left=parent.getPaddingLeft(); int right=parent.getWidth()-parent.getPaddingRight(); String preGroupTitle; String groupTitle=""; for (int i = 0; i < childCount; i++) { View child=parent.getChildAt(i); int pos=parent.getChildLayoutPosition(child); preGroupTitle=groupTitle; groupTitle=mISticky.getGroupTitle(pos); //如果当前分组名和之前分组名一样,忽略此次循环 if (groupTitle.equals(preGroupTitle)) { continue; } //文字的基线,保证显示完全 int textBaseLine=Math.max(mRectHeight,child.getTop()); //分组标题 String title=mISticky.getGroupTitle(pos); int viewBottom=child.getBottom(); //加入限定 防止数组越界 if (pos + 1 < itemCount) { String nextGroupTitle=mISticky.getGroupTitle(pos+1); //当分组不一样 并且改组要向上移动时候 if (!nextGroupTitle.equals(groupTitle) && viewBottom < textBaseLine) { //将上一个往上移动 textBaseLine = viewBottom; } } //绘制边框 c.drawRect(left, textBaseLine - mRectHeight, right, textBaseLine, mRectPaint); //绘制文字并且实现文字居中 int value= (int) Math.abs(mTxtPaint.getFontMetrics().descent +mTxtPaint.getFontMetrics().ascent); c.drawText(title, left, textBaseLine-(mRectHeight+value-mStatusBarHeight)/2, mTxtPaint); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int pos=parent.getChildLayoutPosition(view); if (mISticky.isFirstPosition(pos)) { outRect.top=mRectHeight; outRect.bottom=1; }else { outRect.bottom=1; } } }
6.最后一步 我的Activity和设置虚拟数据:
public class MainActivity extends AppCompatActivity { private RecyclerView mRecyler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * 获取状态栏高度——方法 * */ int statusBarHeight = 0; //获取status_bar_height资源的ID int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { //根据资源ID获取响应的尺寸值 statusBarHeight = getResources().getDimensionPixelSize(resourceId); } mRecyler = (RecyclerView) findViewById(R.id.rv); mRecyler.setLayoutManager(new LinearLayoutManager(this)); //模拟数据 final List<Model> modelList=new ArrayList<>(); for (int i = 0; i < 10; i++) { modelList.add(new Model("标题1","Content:1_"+i,R.mipmap.ic_launcher)); } for (int i = 0; i < 10; i++) { modelList.add(new Model("标题2","Content:2_"+i,R.mipmap.ic_launcher)); } for (int i = 0; i < 10; i++) { modelList.add(new Model("标题3","Content:3_"+i,R.mipmap.ic_launcher)); } for (int i = 0; i < 10; i++) { modelList.add(new Model("标题4","Content:4_"+i,R.mipmap.ic_launcher)); } mRecyler.addItemDecoration(new StickyItemDecoration(this,statusBarHeight, new ISticky() { @Override public boolean isFirstPosition(int pos) { return pos==0|| !modelList.get(pos).getTitle().equals(modelList.get(pos-1).getTitle()); } @Override public String getGroupTitle(int pos) { return modelList.get(pos).getTitle(); } })); mRecyler.setAdapter(new RecyclerAdapter(this,modelList)); } }