使用ItemDecoration自定义RecyclerView的分割线实现头布局

来源:互联网 发布:手机淘宝商家登陆 编辑:程序博客网 时间:2024/04/28 18:53

要实现的效果是仿微信交易记录的头布局

之前做了一个demo,用来实现仿微信交易记录,上面是日期和交易金额,下面是详细记录。滚动的时候隐藏标题,停止显示标题。我以备注的形式来说明,很详细。使用很简单,mRecyclerView.addItemDecoration(new TitleItemDecoration(this,mContentList,mTitleList));//添加itemDecoration,是可以添加多个的

具体代码如下

public class TitleItemDecoration extends RecyclerView.ItemDecoration {    private List<String> mTitleList;    private List<String> mContentList;//存放内容的list,每月的收入和支出    private Paint        mPaint;    private Rect         mBounds;    private Activity     mActivity;    private int          mScreenWidth;    private int          mDensity;    private boolean isScrolling = false;//下面这个方法是第一个调用的,用来给头布局留出空白的地方。    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        if (mContentList.isEmpty()) {            return;        }        int position = parent.getChildAdapterPosition(view);        if (position == 0) {            outRect.set(0, 50 * mDensity, 0, 0);//这个方法相当于是给item设置padding,,给title留出位置来。第一个条目肯定要title        } else if (position > 0) {            if (!mContentList.get(position).substring(0, 6).equals(mContentList.get(position - 1).substring(0, 6))) {                outRect.set(0, 50 * mDensity, 0, 0);//这个方法相当于是给item设置padding            } else {                outRect.set(0, 0, 0, 0);            }        }    }//调用下面方法绘制头布局    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        int left = 10 * mDensity;//10dp的paddingLeft;        int right = 10 * mDensity;//10dp的paddingRight;        if (mContentList.isEmpty()) {            return;        }        for (int i = 0; i < parent.getChildCount(); i++) {            View child = parent.getChildAt(i);//这里应该用这个方法获取child,而onDrawOver不一样            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();            int position = layoutParams.getViewAdapterPosition();//            View child = parent.findViewHolderForLayoutPosition(i).itemView;//获取第i个条目的view,如果用上面的方式,有可能为null            if (position > -1) {//重置后会变成-1,所以要加此判断                if (position == 0) {                    drawDecoration(c, left, position, child);                } else if (!mContentList.get(position).substring(0, 6).equals(mContentList.get(position - 1).substring(0, 6))) {                    drawDecoration(c, left, position, child);                }            }        }    }    private void drawDecoration(Canvas c, int left, int i, View child) {        mPaint.setColor(Color.LTGRAY);        //top为第一个条目top-高度50,也就是从0开始//        c.drawRect(0, child.getTop() - 50 * mDensity, mScreenWidth, child.getTop(), mPaint);        mPaint.setColor(Color.RED);        //下面一行,设置文字的区域范围,参数1:文字内容也就是title,因为我写的title和content的前6个字符是一样的,所以就直接写内容的前6字符了        //参数2:文字起始位置为0,参数3:文字终止位置,为文字长度,参数4,Rec是我们定义的mBounds        mPaint.getTextBounds(mContentList.get(i).substring(0, 6), 0, mContentList.get(i).substring(0, 6).length(), mBounds);        //下面一行,画文字。参数1:文字内容,参数2:文字坐标x,参数3:文字坐标y,参数4,paint//                c.drawText(mContentList.get(i).substring(0,6),0,child.getTop()-mBounds.top,mPaint);//                下一行解释:参数2:文字离左边距离,参数3,文字离上面距离,其中child.getTop是子控件距离上面高度,mBound.top是系统自带的//                偏移量,需要减去文字才能回到原点,-50*mDensity是一行的高度,因为文字不是从第一个子控件开始画的而是从第一个子控件上面一行//                开始画的,(50-14)/2*mDensity是文字的padding,一行的高度减去文字高度,然后除以2就是文字距离上面的padding了        c.drawText(mContentList.get(i).substring(0, 6), left, child.getTop() - mBounds.top - 50 * mDensity + (50 - 14) / 2 * mDensity, mPaint);    }    public TitleItemDecoration(Activity activity, List<String> contentList, List<String> titleList) {        super();        mActivity = activity;        mTitleList = titleList;//注意titleList是肯定要用的,这里因为我的ContentList内容各个条目的前6个字符等于titleList内容,所以直接用ContentList的前6个字符填充title了,就没有用到titleListle了        mContentList = contentList;        init();    }    private void init() {        mPaint = new Paint();        mPaint.setAntiAlias(true);        mBounds = new Rect();//        WindowManager windowManager = mActivity.getWindowManager();//        mScreenWidth = windowManager.getDefaultDisplay().getWidth();        DisplayMetrics displayMetrics = mActivity.getResources().getDisplayMetrics();        mDensity = (int) displayMetrics.density;        mScreenWidth = displayMetrics.widthPixels;        mPaint.setTextSize(14*mDensity);    }//下面方法是在onDraw之后执行的,那么我们可以绘制一个布局在最顶端,实现顶端一直有最新的头    @Override    public void onDrawOver(final Canvas c, final RecyclerView parent, RecyclerView.State state) {        super.onDrawOver(c, parent, state);        parent.addOnScrollListener(new RecyclerView.OnScrollListener() {//RecyclerView可以添加多个滚动监听,所以不会和外面的监听冲突//这里监听滚动的时候是否显示头布局            @Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                if (newState == RecyclerView.SCROLL_STATE_IDLE) {                    isScrolling = false;                    //该方法画的不是在顶层,而是和条目重叠                } else {                    isScrolling = true;                }            }        });        if (!isScrolling) {            addDecorationOver(parent, c);        }    }    private void addDecorationOver(RecyclerView parent, Canvas c) {        if (mContentList.isEmpty()) {            return;        }        //获取第一个可见条目        LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();        int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();//                    View child = parent.findViewHolderForAdapterPosition(firstVisibleItemPosition).itemView;//这里要用此方法获取child        int left = 10 * mDensity;//10dp的paddingLeft;        int right = 10 * mDensity;//10dp的paddingRight;        mPaint.setColor(Color.LTGRAY);        //top为第一个条目top-高度50,也就是从0开始//        c.drawRect(0, 0, mScreenWidth, 50 * mDensity, mPaint);//直接画在第一行,top一般是parent.getPaddintTop,我直接写0了        mPaint.setColor(Color.RED);        mPaint.getTextBounds(mContentList.get(firstVisibleItemPosition).substring(0, 6), 0, mContentList.get(firstVisibleItemPosition).substring(0, 6).length(), mBounds);        c.drawText(mContentList.get(firstVisibleItemPosition).substring(0, 6), left, -mBounds.top + (50 - 14) / 2 * mDensity, mPaint);    }}
原创粉丝点击