RecyclerView轻松实现悬浮头部分组列表

2017-01-14 19:44:35来源:CSDN作者:binbinqq86人点击

第七城市

转载请注明出处:http://blog.csdn.net/binbinqq86/article/details/54427505

关于RecyclerView的使用,相信大家都不陌生,并且功能的强大早已让众多开发者臣服,本篇主要讲解联系人列表效果的悬浮头部分组列表的实现,先上效果图:

一般的思路应该是利用RecyclerView的itemType来区分标题和下面的子数据而采用不同的布局,再加上RecyclerView的滚动监听来实现头部的悬浮标题移动、隐藏、显示。本篇的主要思路是从ItemDecoration下手,说到这里我想你应该心中有个眉目了,如果对ItemDecoration还不熟悉的朋友,可以去看我的前两篇文章:

  • RecyclerView之ItemDecoration详解(上)
  • RecyclerView之ItemDecoration详解(下)

先上代码:

@Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        int pos=parent.getChildViewHolder(view).getAdapterPosition();        if(keys.containsKey(pos)){//留出头部偏移            outRect.set(0,mTitleHeight,0,0);        }else{            outRect.set(0,dividerHeight,0,0);        }    }

首先就是根据当前view的position判断需要在上方留出分割线空隙还是标题栏头部空隙。

然后是onDraw方法绘制具体的分割线和标题栏,看代码:

private void drawVertical(Canvas c, RecyclerView parent){        int left = parent.getPaddingLeft();        int right = parent.getWidth() - parent.getPaddingRight();        int top=0;        int bottom=0;        for (int i = 0; i < parent.getChildCount(); i++) {            View child=parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();            if(!keys.containsKey(params.getViewLayoutPosition())){                //画普通分割线                top=child.getTop()-params.topMargin-dividerHeight;                bottom=top+dividerHeight;                mDivider.setBounds(left, top, right, bottom);                mDivider.draw(c);            }else{                //画头部                top=child.getTop()-params.topMargin-mTitleHeight;                bottom=top+mTitleHeight;                c.drawRect(left,top,right,bottom,mBackgroundPaint);                float x=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,mContext.getResources().getDisplayMetrics());                float y=bottom - (mTitleHeight - mTextHeight) / 2 - mTextBaselineOffset;//计算文字baseLine                c.drawText(keys.get(params.getViewLayoutPosition()),x,y,mTextPaint);            }        }    }

其中用到了canvas.drawText方法,这里需要注意y坐标的计算,文本的绘制是根据baseLine来进行的,不懂的朋友可以去网上查阅相关的知识,本文不再重点讲解。

最后就是onDrawOver方法的实现,该方法主要用来在RecyclerView最上层绘制,这样当列表滚动的时候,可以绘制标题栏,这样就看上去就一直悬浮在页面顶部,主要难点就是去判断上下两组标题栏的碰撞,下面看代码:

@Override    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {        super.onDrawOver(c, parent, state);        if(!showFloatingHeaderOnScrolling){            return;        }        int firstVisiblePos=((LinearLayoutManager)parent.getLayoutManager()).findFirstVisibleItemPosition();        if(firstVisiblePos==RecyclerView.NO_POSITION){            return;        }        String title=getTitle(firstVisiblePos);        if(TextUtils.isEmpty(title)){            return;        }        boolean flag=false;        if(getTitle(firstVisiblePos+1)!=null&&!title.equals(getTitle(firstVisiblePos+1))){            //说明是当前组最后一个元素,但不一定碰撞了            View child=parent.findViewHolderForAdapterPosition(firstVisiblePos).itemView;            if(child.getTop()+child.getMeasuredHeight()<mTitleHeight){                //进一步检测碰撞                c.save();//保存画布当前的状态                flag=true;                c.translate(0,child.getTop()+child.getMeasuredHeight()-mTitleHeight);//负的代表向上            }        }        int left = parent.getPaddingLeft();        int right = parent.getWidth() - parent.getPaddingRight();        int top=parent.getPaddingTop();        int bottom=top+mTitleHeight;        c.drawRect(left,top,right,bottom,mBackgroundPaint);        float x=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,mContext.getResources().getDisplayMetrics());        float y=bottom - (mTitleHeight - mTextHeight) / 2 - mTextBaselineOffset;//计算文字baseLine        c.drawText(title,x,y,mTextPaint);        if(flag){            //还原画布为初始状态            c.restore();        }    }

注意第四行,我加了个变量来控制是否需要悬浮头部的效果,如果不需要则直接返回,只有分组列表的效果。而getTitle方法主要是用来获取每个item的title,碰撞的检测主要是根据当前第一个可见元素和下一个元素进行对比,也就是代码第16行,如果这两个元素所在的title不一样,就说明是属于不同的分组,标题栏即将进行碰撞了,当然这样检测还是不够的,还需要根据item的高度和标题栏的高度结合item的getTop值来共同判断,这样就可以去移动画布,造成标题栏被下一个挤上去的效果,同时需要在下面还原移动过的画布。

怎么样,整个逻辑和过程就讲解完了,实现起来简单吧,有疑问的朋友可以在下面留言~~~

源码下载,请点击这里

第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台