Android 通讯录(1)-----自定义ItemDecoration实现分类标题

来源:互联网 发布:如何制作淘宝首页模板 编辑:程序博客网 时间:2024/05/21 23:26

前言

RecyclerView 相信大家都不陌生,画分割线一般有两种思路:

  1. 在itemView的布局文件中留出空挡,或者干脆画条线。
  2. recyclerView.addItemDecoration() 添加。

其中第二种如果不自定义的话,只能加默认的线条,且只能在LinearLayoutManager中使用。

最终效果

这里写图片描述

当然了,这是最终效果,这篇文章我们只考虑左边的分类标题,右边的,我们下集更精彩。

写代码之前

自定义View,在写之前我们就需要确认自己需要实现的目标有哪些,比如:

  • 标题栏高度
  • 标题栏背景色
  • 标题栏字体大小

这些是我这个demo中准备实现的。

ItemDecoration主要方法

新建一个类继承RecyclerView.ItemDecoration,需要实现的方法总共也就3个:

  • getItemOffsets:可以理解为给RecyclerView中的item设置padding
  • onDraw:就是自定view里那个常见的onDraw,画出想画的内容。
  • onDrawOver:Over用的很精髓,其实跟onDraw差不多,也是画。只是在onDraw执行完成后才画,表现为所画内容在itemView的上层。
public class TitleItemDecoration extends RecyclerView.ItemDecoration {    private Context mContext;    private List<CityBean> mData;    private Paint mPaint;    private Rect mBounds;    //标题栏背景色    private static int COLOR_TITLE_BG = Color.parseColor("#FFDFDFDF");    //标题栏字体颜色    private static int COLOR_TITLE_FONT = Color.parseColor("#FF000000");    private int titleSize;    private int titleHeight;    public TitleItemDecoration(Context mContext, List<CityBean> mData) {        this.mContext = mContext;        this.mData = mData;        //预先设置标题栏高度        titleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,30,mContext.getResources().getDisplayMetrics());        //预先设置标题栏字体大小        titleSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,mContext.getResources().getDisplayMetrics());        mPaint = new Paint();        //抗锯齿        mPaint.setAntiAlias(true);        mBounds = new Rect();    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        int position = ((RecyclerView.LayoutParams)view.getLayoutParams()).getViewAdapterPosition();        if(position>-1){            //在合适的位置 空出标题栏的高度            if(position == 0){                outRect.set(0,titleHeight,0,0);            }else if(!mData.get(position).getTag().equals(mData.get(position - 1).getTag())){                outRect.set(0,titleHeight,0,0);            }        }    }    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        super.onDraw(c, parent, state);        int left = parent.getPaddingLeft();        int right = parent.getWidth() - parent.getPaddingRight();        for (int i = 0;i<parent.getChildCount();i++){            View childView = parent.getChildAt(i);            int position = ((RecyclerView.LayoutParams)childView.getLayoutParams()).getViewAdapterPosition();            if(position >-1){                if(position == 0){                    drawTitle(c,left,right,childView,position);                }else if(!mData.get(position).getTag().equals(mData.get(position - 1).getTag())){                    drawTitle(c,left,right,childView,position);                }            }        }    }    private void drawTitle(Canvas c, int left, int right, View childView, int position) {        //画笔设置颜色为背景色        mPaint.setColor(COLOR_TITLE_BG);        //画矩形        c.drawRect(left,childView.getTop() - titleHeight,right,childView.getTop(),mPaint);        //画笔设置颜色为字体颜色        mPaint.setColor(COLOR_TITLE_FONT);        //画笔设置字体大小        mPaint.setTextSize(titleSize);        //获取容纳字的矩形框大小        mPaint.getTextBounds(mData.get(position).getTag(),0,mData.get(position).getTag().length(),mBounds);        //画字        c.drawText(mData.get(position).getTag(),childView.getPaddingLeft()        ,childView.getTop() - (titleHeight/2 - mBounds.height()/2),mPaint);    }    @Override    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {        super.onDrawOver(c, parent, state);        boolean flag = false;//标志量:画布是否移动        int position = ((LinearLayoutManager)parent.getLayoutManager()).findFirstVisibleItemPosition();        View childView = parent.findViewHolderForLayoutPosition(position).itemView;        if(position + 1 < mData.size() && mData.get(position).getTag()!=null && !mData.get(position).getTag().equals(mData.get(position + 1).getTag())){            //临界点            if(childView.getHeight() + childView.getTop() < titleHeight){                //保存画布状态                c.save();                flag = true;                //画布移动                c.translate(0,childView.getHeight() + childView.getTop() - titleHeight);            }        }        mPaint.setColor(COLOR_TITLE_BG);        c.drawRect(parent.getPaddingLeft(),parent.getPaddingTop(),parent.getWidth() - parent.getPaddingRight(),parent.getPaddingTop() + titleHeight,mPaint);        mPaint.setColor((COLOR_TITLE_FONT));        mPaint.getTextBounds(mData.get(position).getTag(),0,mData.get(position).getTag().length(),mBounds);        c.drawText(mData.get(position).getTag(),childView.getPaddingLeft(),parent.getPaddingTop() + titleHeight - (titleHeight/2 - mBounds.height()/2),mPaint);        if(flag)            c.restore();    }}

14-25行:构造函数,还有自定义view的一些常规设置:预先设置好字体大小、颜色,或者自定义的一些属性值。

33-37行:在合适的位置,设置padding值,将分类标题所需要的预设高度给留出来。

72行:childView.getPaddingLeft()是为了控制方便,遵守itemView布局时的padding值。

83行:临界点可以自己画个图思考下。注意,第一个可见的item是顶部的分类标题遮住的那个。

85和97行 是一对儿:如果要想对整个画布进行操作,必须这样做,否则其他元素会出问题。

demo

点我下载

感兴趣的朋友可以继续阅读 Android 通讯录(2)—–自定义View实现右侧导航栏

阅读全文
1 0