当前位置: 移动技术网 > 移动技术>移动开发>Android > Android仿微信通讯录打造带悬停头部的分组列表(上)

Android仿微信通讯录打造带悬停头部的分组列表(上)

2019年07月24日  | 移动技术网移动技术  | 我要评论

一 概述

本文是android导航分组列表系列上,因时间和篇幅原因分上下,最终上下合璧,完整版效果如下:

 

上部残卷效果如下:两个itemdecoration,一个实现悬停头部分组列表功能,一个实现分割线(官方demo)

网上关于实现带悬停分组头部的列表的方法有很多,像我看过有主席的自定义expandlistview实现的,也看过有人用一个额外的父布局里面套 recyclerview/listview+一个头部view(位置固定在父布局上方)实现的。
对于以上解决方案,有以下几点个人觉得不好的地方:
1. 现在recyclerview是主流
2. 在recyclerview外套一个父布局总归是增加布局层级容易overdraw,显得不够优雅。
3. item布局实现带这种分类头部的方法有两种,一种是把分类头部当做一种itemviewtype(麻烦),另一种是每个item布局都包含了分类头部的布局,代码里根据postion等信息动态visible,gone头部(布局冗余,item效率降低)。
况且google为我们提供了itemdecoration,它本身就是用来修饰recyclerview里的item的,它的getitemoffsets() ondraw()方法用于为item分类头部留出空间和绘制(解决缺点3),它的ondrawover()方法用于绘制悬停的头部view(解决缺点2)。
而且更重要的是,itemdecoration出来这么久了,你还不用它?
本文就利用itemdecoration 打造 分组列表,并配有悬停头部功能。

亮点预览:添加多个itemdecoration、它们的执行顺序、itemdecoration方法执行顺序、itemdecoration和recyclerview的绘制顺序

二 使用itemdecoration

用法:为recyclerviewpool添加一个或多个itemdecoration

 //如果add多个,那么按照先后顺序,依次渲染。
 mrv.additemdecoration(mdecoration = new titleitemdecoration(this, mdatas));
 mrv.additemdecoration(new titleitemdecoration2(this,mdatas));
 mrv.additemdecoration(new divideritemdecoration(mainactivity.this,divideritemdecoration.vertical_list));

为recyclerview添加itemdecoration只要这么一句additemdecoration(),
它有两个同名重载方法:
additemdecoration(itemdecoration decor) 常用,(按照add顺序,依次渲染itemdecoration)
additemdecoration(itemdecoration decor, int index) add一个itemdecoration,并为它指定顺序
上来就高能,别的讲解recyclerview的文章一般都是对itemdecoration一笔带过,用的demo一般也都是官方的divideritemdecoration类,更别提还添加多个itemdecoration了。其实我也是昨天写demo的时候才发现这个方法,点进去查看了一下源码:

 public void additemdecoration(itemdecoration decor) {
 additemdecoration(decor, -1);
 }

 public void additemdecoration(itemdecoration decor, int index) {
 if (mlayout != null) {
  mlayout.assertnotinlayoutorscroll("cannot add item decoration during a scroll or"
   + " layout");
 }
 if (mitemdecorations.isempty()) {
  setwillnotdraw(false);
 }
 if (index < 0) {
  mitemdecorations.add(decor);
 } else {
  mitemdecorations.add(index, decor);
 }
 markitemdecorinsetsdirty();
 requestlayout();
 }

老套路:我们最常用的单参数方法 内部调用了双参数方法,并把index 传入-1。
我们add的itemdecoration 都存储在recyclerview类的mitemdecorations变量里,
这个变量就是一个arraylist,定义如下

private final arraylist<itemdecoration> mitemdecorations = new arraylist<>();

三 itemdecoration方法介绍和编写

常用(全部)方法:

按照在recyclerview中它们被调用的顺序排列:
1. public void getitemoffsets(rect outrect, view view, recyclerview parent, recyclerview.state state)
2. public void ondraw(canvas c, recyclerview parent, recyclerview.state state)
3. public void ondrawover(canvas c, recyclerview parent, recyclerview.state state)
这个三个方法也是继承一个itemdecoration必须实现的三个方法。(其实itemdecoration里除了@deprecated 的方法 也就它们三了,)

方法一的编写
public void getitemoffsets(rect outrect, view view, recyclerview parent, recyclerview.state state):
我们需要利用 parent和state变量,来获取需要的辅助信息,例如postion, 最终调用outrect.set(int left, int top, int right, int bottom)方法,设置四个方向上 需要为itemview设置padding的值。
下图我觉得很经典:摘自(https://blog.piasy.com/2016/03/26/insight-android-recyclerview-itemdecoration/?utm_source=tuicool&utm_medium=referral)向作者表示感谢。如作者不许我转图,烦请联系我删除

本文的 实体bean如下编写:

/**
 * created by zhangxutong .
 * date: 16/08/28
 */

public class citybean {
 private string tag;//所属的分类(城市的汉语拼音首字母)
 private string city;

 public citybean(string tag, string city) {
 this.tag = tag;
 this.city = city;
 }

 public string gettag() {
 return tag;
 }

 public void settag(string tag) {
 this.tag = tag;
 }

 public string getcity() {
 return city;
 }

 public void setcity(string city) {
 this.city = city;
 }
}

getitemoffsets方法 如下:
通过parent获取postion信息,通过postion拿到数据里的每个bean里的分类,因为数据集已经有序,如果与前一个分类不一样,说明是一个新的分类,则需要绘制头部outrect.set(0, mtitleheight, 0, 0);,否则不需要outrect.set(0, 0, 0, 0);。

 @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()).getviewlayoutposition();
 //我记得rv的item position在重置时可能为-1.保险点判断一下吧
 if (position > -1) {
  if (position == 0) {//等于0肯定要有title的
  outrect.set(0, mtitleheight, 0, 0);
  } else {//其他的通过判断
  if (null != mdatas.get(position).gettag() && !mdatas.get(position).gettag().equals(mdatas.get(position - 1).gettag())) {
   outrect.set(0, mtitleheight, 0, 0);//不为空 且跟前一个tag不一样了,说明是新的分类,也要title
  } else {
   outrect.set(0, 0, 0, 0);
  }
  }
 }
 }

--------------------------------------------------------------------------------

方法二的编写

public void ondraw(canvas c, recyclerview parent, recyclerview.state state)

我们需要利用 parent和state变量,来获取需要的辅助信息,例如绘制的上下左右,childcount, childview等。。最终利用c调用canvas的方法来绘制出我们想要的ui。会自定义view就会写本方法~
ondraw绘制出的内容是在itemview下层,虽然它可以绘制超出getitemoffsets()里的rect区域,但是超出区域最终不会显示,但被itemview覆盖的区域会产生overdraw。
本文如下编写:通过parent获取绘制ui的 left和right以及childcount, 遍历childview,根据childview的postion,和方法一中的判断方法一样,来决定是否绘制分类title区域:
分类绘制title的方法就是自定义view的套路,根据确定的上下左右范围先drawrect绘制一个背景,然后drawtext绘制文字。
(不会自定义view的可参考郭神 洋神 文章:
)。

 @override
 public void ondraw(canvas c, recyclerview parent, recyclerview.state state) {
 super.ondraw(c, parent, state);
 final int left = parent.getpaddingleft();
 final int right = parent.getwidth() - parent.getpaddingright();
 final int childcount = parent.getchildcount();
 for (int i = 0; i < childcount; i++) {
  final view child = parent.getchildat(i);
  final recyclerview.layoutparams params = (recyclerview.layoutparams) child
   .getlayoutparams();
  int position = params.getviewlayoutposition();
  //我记得rv的item position在重置时可能为-1.保险点判断一下吧
  if (position > -1) {
  if (position == 0) {//等于0肯定要有title的
   drawtitlearea(c, left, right, child, params, position);

  } else {//其他的通过判断
   if (null != mdatas.get(position).gettag() && !mdatas.get(position).gettag().equals(mdatas.get(position - 1).gettag())) {
   //不为空 且跟前一个tag不一样了,说明是新的分类,也要title
   drawtitlearea(c, left, right, child, params, position);
   } else {
   //none
   }
  }
  }
 }
 }

 /**
 * 绘制title区域背景和文字的方法
 *
 * @param c
 * @param left
 * @param right
 * @param child
 * @param params
 * @param position
 */
 private void drawtitlearea(canvas c, int left, int right, view child, recyclerview.layoutparams params, int position) {//最先调用,绘制在最下层
 mpaint.setcolor(color_title_bg);
 c.drawrect(left, child.gettop() - params.topmargin - mtitleheight, right, child.gettop() - params.topmargin, mpaint);
 mpaint.setcolor(color_title_font);
 mpaint.gettextbounds(mdatas.get(position).gettag(), 0, mdatas.get(position).gettag().length(), mbounds);
 c.drawtext(mdatas.get(position).gettag(), child.getpaddingleft(), child.gettop() - params.topmargin - (mtitleheight / 2 - mbounds.height() / 2), mpaint);
 }

写完 12 方法,就已经完成了分类列表title的绘制,方法3实现顶部悬停title效果:go

--------------------------------------------------------------------------------

方法三的编写

public void ondrawover(canvas c, recyclerview parent, recyclerview.state state):

和 ondraw()方法类似, 我们需要利用 parent和state变量,来获取需要的辅助信息,例如绘制的上下左右,position, childview等。。最终利用c调用canvas的方法来绘制出我们想要的ui。同样是会自定义view就会写本方法~
ondrawover绘制出的内容是在recyclerview的最上层,会遮挡住itemview,so天生自带悬停效果,用来绘制悬停view再好不过。
本文如下编写:首先通过parent获取layoutmanager(由于悬停分组列表的特殊性,写死了是linearlayoutmanger),然后获取当前第一个可见itemview以及postion,以及它所属的分类title(tag),然后绘制悬停view的背景和文字(tag),可参考方法2里的书写,大同小异。

 @override
 public void ondrawover(canvas c, recyclerview parent, recyclerview.state state) {//最后调用 绘制在最上层
 int pos = ((linearlayoutmanager)(parent.getlayoutmanager())).findfirstvisibleitemposition();

 string tag = mdatas.get(pos).gettag();
 view child = parent.getchildat(pos);
 mpaint.setcolor(color_title_bg);
 c.drawrect(parent.getpaddingleft(), parent.getpaddingtop(), parent.getright() - parent.getpaddingright(), parent.getpaddingtop() + mtitleheight, mpaint);
 mpaint.setcolor(color_title_font);
 mpaint.gettextbounds(tag, 0, tag.length(), mbounds);
 c.drawtext(tag, child.getpaddingleft(),
  parent.getpaddingtop() + mtitleheight - (mtitleheight / 2 - mbounds.height() / 2),
  mpaint);
 }

至此,我们的 带悬停头部的分组列表的itemdecoration就编写完毕了,完整代码如下:

四 分类title itemdecoration完整代码:

/**
 * 有分类title的 itemdecoration
 * created by zhangxutong .
 * date: 16/08/28
 */

public class titleitemdecoration extends recyclerview.itemdecoration {
 private list<citybean> mdatas;
 private paint mpaint;
 private rect mbounds;//用于存放测量文字rect

 private int mtitleheight;//title的高
 private static int color_title_bg = color.parsecolor("#ffdfdfdf");
 private static int color_title_font = color.parsecolor("#ff000000");
 private static int mtitlefontsize;//title字体大小


 public titleitemdecoration(context context, list<citybean> datas) {
 super();
 mdatas = datas;
 mpaint = new paint();
 mbounds = new rect();
 mtitleheight = (int) typedvalue.applydimension(typedvalue.complex_unit_dip, 30, context.getresources().getdisplaymetrics());
 mtitlefontsize = (int) typedvalue.applydimension(typedvalue.complex_unit_sp, 16, context.getresources().getdisplaymetrics());
 mpaint.settextsize(mtitlefontsize);
 mpaint.setantialias(true);
 }

 @override
 public void ondraw(canvas c, recyclerview parent, recyclerview.state state) {
 super.ondraw(c, parent, state);
 final int left = parent.getpaddingleft();
 final int right = parent.getwidth() - parent.getpaddingright();
 final int childcount = parent.getchildcount();
 for (int i = 0; i < childcount; i++) {
  final view child = parent.getchildat(i);
  final recyclerview.layoutparams params = (recyclerview.layoutparams) child
   .getlayoutparams();
  int position = params.getviewlayoutposition();
  //我记得rv的item position在重置时可能为-1.保险点判断一下吧
  if (position > -1) {
  if (position == 0) {//等于0肯定要有title的
   drawtitlearea(c, left, right, child, params, position);

  } else {//其他的通过判断
   if (null != mdatas.get(position).gettag() && !mdatas.get(position).gettag().equals(mdatas.get(position - 1).gettag())) {
   //不为空 且跟前一个tag不一样了,说明是新的分类,也要title
   drawtitlearea(c, left, right, child, params, position);
   } else {
   //none
   }
  }
  }
 }
 }

 /**
 * 绘制title区域背景和文字的方法
 *
 * @param c
 * @param left
 * @param right
 * @param child
 * @param params
 * @param position
 */
 private void drawtitlearea(canvas c, int left, int right, view child, recyclerview.layoutparams params, int position) {//最先调用,绘制在最下层
 mpaint.setcolor(color_title_bg);
 c.drawrect(left, child.gettop() - params.topmargin - mtitleheight, right, child.gettop() - params.topmargin, mpaint);
 mpaint.setcolor(color_title_font);
/*
 paint.fontmetricsint fontmetrics = mpaint.getfontmetricsint();
 int baseline = (getmeasuredheight() - fontmetrics.bottom + fontmetrics.top) / 2 - fontmetrics.top;*/

 mpaint.gettextbounds(mdatas.get(position).gettag(), 0, mdatas.get(position).gettag().length(), mbounds);
 c.drawtext(mdatas.get(position).gettag(), child.getpaddingleft(), child.gettop() - params.topmargin - (mtitleheight / 2 - mbounds.height() / 2), mpaint);
 }

 @override
 public void ondrawover(canvas c, recyclerview parent, recyclerview.state state) {//最后调用 绘制在最上层
 int pos = ((linearlayoutmanager)(parent.getlayoutmanager())).findfirstvisibleitemposition();

 string tag = mdatas.get(pos).gettag();
 view child = parent.getchildat(pos);
 mpaint.setcolor(color_title_bg);
 c.drawrect(parent.getpaddingleft(), parent.getpaddingtop(), parent.getright() - parent.getpaddingright(), parent.getpaddingtop() + mtitleheight, mpaint);
 mpaint.setcolor(color_title_font);
 mpaint.gettextbounds(tag, 0, tag.length(), mbounds);
 c.drawtext(tag, child.getpaddingleft(),
  parent.getpaddingtop() + mtitleheight - (mtitleheight / 2 - mbounds.height() / 2),
  mpaint);
 }

 @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()).getviewlayoutposition();
 //我记得rv的item position在重置时可能为-1.保险点判断一下吧
 if (position > -1) {
  if (position == 0) {//等于0肯定要有title的
  outrect.set(0, mtitleheight, 0, 0);
  } else {//其他的通过判断
  if (null != mdatas.get(position).gettag() && !mdatas.get(position).gettag().equals(mdatas.get(position - 1).gettag())) {
   outrect.set(0, mtitleheight, 0, 0);//不为空 且跟前一个tag不一样了,说明是新的分类,也要title
  } else {
   outrect.set(0, 0, 0, 0);
  }
  }
 }
 }

}

/**
 * 有分类title的 itemdecoration
 * created by zhangxutong .
 * date: 16/08/28
 */

public class titleitemdecoration extends recyclerview.itemdecoration {
 private list<citybean> mdatas;
 private paint mpaint;
 private rect mbounds;//用于存放测量文字rect

 private int mtitleheight;//title的高
 private static int color_title_bg = color.parsecolor("#ffdfdfdf");
 private static int color_title_font = color.parsecolor("#ff000000");
 private static int mtitlefontsize;//title字体大小


 public titleitemdecoration(context context, list<citybean> datas) {
 super();
 mdatas = datas;
 mpaint = new paint();
 mbounds = new rect();
 mtitleheight = (int) typedvalue.applydimension(typedvalue.complex_unit_dip, 30, context.getresources().getdisplaymetrics());
 mtitlefontsize = (int) typedvalue.applydimension(typedvalue.complex_unit_sp, 16, context.getresources().getdisplaymetrics());
 mpaint.settextsize(mtitlefontsize);
 mpaint.setantialias(true);
 }

 @override
 public void ondraw(canvas c, recyclerview parent, recyclerview.state state) {
 super.ondraw(c, parent, state);
 final int left = parent.getpaddingleft();
 final int right = parent.getwidth() - parent.getpaddingright();
 final int childcount = parent.getchildcount();
 for (int i = 0; i < childcount; i++) {
  final view child = parent.getchildat(i);
  final recyclerview.layoutparams params = (recyclerview.layoutparams) child
   .getlayoutparams();
  int position = params.getviewlayoutposition();
  //我记得rv的item position在重置时可能为-1.保险点判断一下吧
  if (position > -1) {
  if (position == 0) {//等于0肯定要有title的
   drawtitlearea(c, left, right, child, params, position);

  } else {//其他的通过判断
   if (null != mdatas.get(position).gettag() && !mdatas.get(position).gettag().equals(mdatas.get(position - 1).gettag())) {
   //不为空 且跟前一个tag不一样了,说明是新的分类,也要title
   drawtitlearea(c, left, right, child, params, position);
   } else {
   //none
   }
  }
  }
 }
 }

 /**
 * 绘制title区域背景和文字的方法
 *
 * @param c
 * @param left
 * @param right
 * @param child
 * @param params
 * @param position
 */
 private void drawtitlearea(canvas c, int left, int right, view child, recyclerview.layoutparams params, int position) {//最先调用,绘制在最下层
 mpaint.setcolor(color_title_bg);
 c.drawrect(left, child.gettop() - params.topmargin - mtitleheight, right, child.gettop() - params.topmargin, mpaint);
 mpaint.setcolor(color_title_font);
/*
 paint.fontmetricsint fontmetrics = mpaint.getfontmetricsint();
 int baseline = (getmeasuredheight() - fontmetrics.bottom + fontmetrics.top) / 2 - fontmetrics.top;*/

 mpaint.gettextbounds(mdatas.get(position).gettag(), 0, mdatas.get(position).gettag().length(), mbounds);
 c.drawtext(mdatas.get(position).gettag(), child.getpaddingleft(), child.gettop() - params.topmargin - (mtitleheight / 2 - mbounds.height() / 2), mpaint);
 }

 @override
 public void ondrawover(canvas c, recyclerview parent, recyclerview.state state) {//最后调用 绘制在最上层
 int pos = ((linearlayoutmanager)(parent.getlayoutmanager())).findfirstvisibleitemposition();

 string tag = mdatas.get(pos).gettag();
 view child = parent.getchildat(pos);
 mpaint.setcolor(color_title_bg);
 c.drawrect(parent.getpaddingleft(), parent.getpaddingtop(), parent.getright() - parent.getpaddingright(), parent.getpaddingtop() + mtitleheight, mpaint);
 mpaint.setcolor(color_title_font);
 mpaint.gettextbounds(tag, 0, tag.length(), mbounds);
 c.drawtext(tag, child.getpaddingleft(),
  parent.getpaddingtop() + mtitleheight - (mtitleheight / 2 - mbounds.height() / 2),
  mpaint);
 }

 @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()).getviewlayoutposition();
 //我记得rv的item position在重置时可能为-1.保险点判断一下吧
 if (position > -1) {
  if (position == 0) {//等于0肯定要有title的
  outrect.set(0, mtitleheight, 0, 0);
  } else {//其他的通过判断
  if (null != mdatas.get(position).gettag() && !mdatas.get(position).gettag().equals(mdatas.get(position - 1).gettag())) {
   outrect.set(0, mtitleheight, 0, 0);//不为空 且跟前一个tag不一样了,说明是新的分类,也要title
  } else {
   outrect.set(0, 0, 0, 0);
  }
  }
 }
 }

}

五 一些itemdecoration的相关补充姿势

1. 多个itemdecoration,以及它们的绘制顺序。
就像第二节中的用法提到的,可以为一个recyclerview添加多个itemdecoration,那么多个itemdecoration的绘制顺序是什么呢:我们看看源码吧:
第二节中提到,多个itemdecoration最终是存储在recyclerview里的mitemdecorations(arraylist)变量中,那我们就去recyclerview的 源码里搜一搜,看看哪些地方用到了mitemdecorations。
发现在draw()和ondraw()方法里:按照在mitemdecorations里的postion顺序,依次调用了每个itemdecoration的ondrawover和ondraw方法。所以后添加的itemdecoration,如果和前面的itemdecoration的绘制区域有重合的地方,会遮盖住前面的itemdecoration(overdraw)。

 @override
 public void draw(canvas c) {
 super.draw(c);

 final int count = mitemdecorations.size();
 for (int i = 0; i < count; i++) {
  mitemdecorations.get(i).ondrawover(c, this, mstate);
 }

 @override
 public void ondraw(canvas c) {
 super.ondraw(c);

 final int count = mitemdecorations.size();
 for (int i = 0; i < count; i++) {
  mitemdecorations.get(i).ondraw(c, this, mstate);
 }
 }

2. itemdecoration和recyclerview的item的绘制顺序。
在介绍itemdecoration的三个方法时,我们提到过结论:
itemdecoration的ondraw最先调用,绘制在最底层, 其上再绘制itemview 中间层, 再上调用itemdecoration的ondrawover,绘制在最上层。
理由:
由上面代码可见, recyclerview的draw()方法中,在super.draw(c)方法调用完后,才调用mitemdecorations.get(i).ondrawover(c, this, mstate); 而super.draw(c)方法就是直接调用view的public void draw(canvas canvas) 方法,如下所示:
其中又先调用了view(recyclerview)的ondraw()方法,
在recyclerview的ondraw()方法中,会调用mitemdecorations.get(i).ondraw(c, this, mstate);
所以ondraw最先调用,绘制在最底层
后调用了view(viewgroup)的dispatchdraw(canvas)方法;
在viewgroup的dispatchdraw(canvas)方法里,会执行 drawchild(canvas canvas, view child, long drawingtime)方法,绘制每个itemview。
所以itemview绘制在中间层
最后super.draw(c)走完,调用mitemdecorations.get(i).ondrawover(c, this, mstate);
所以再上调用itemdecoration的ondrawover,绘制在最上层。 (从方法名字也可以看出哈)
view的draw()方法如下,

 /**
 * this method is called by viewgroup.drawchild() to have each child view draw itself.
 *
 * this is where the view specializes rendering behavior based on layer type,
 * and hardware acceleration.
 */
 boolean draw(canvas canvas, viewgroup parent, long drawingtime) {
 ............省略
 // step 3, draw the content
 if (!dirtyopaque) ondraw(canvas);

 // step 4, draw the children
 dispatchdraw(canvas);

六 完整代码地址

csdn代码上传中

欢迎光临我的github下载上下合集demo:喜欢的随手点个star 哈~
https://github.com/mcxtzhang/demos/tree/master/itemdecorationdemo
master分支为上部残篇,sidebar分支为上下合璧完整篇。

七 总结

本文是我第一次用markdown编写博客,感觉一个字爽。
recyclerview相关的各个类,个个是宝,每一次探索都觉得如获至宝, 感觉利用itemdecoration可以干很多事,可惜itemdecoration貌似不能接受到用户的点击事件~要不我右侧导航栏都想用itemdecoration实现了。
关于可以add多个itemdecoration这一点,想了一下,觉得很精妙,这是一种很好的设计思想,多个itemdecoration各司其职,如本文,采用官方itemdecoration作分割线,自己又写一个itemdecoration作分类title和分类title相关的悬停title。用时根据需要,选择任意数量的“装饰品”itemdecoration,来丰富你的recyclerview。可能我的low常规思想还是一个xxx类,使用时如果扩充功能,需要extends and code~但这样不同的功能就太耦合了,不利于复用。毕竟 “组合大于继承”。
这一周亚历山大,工作上的事很多,下篇原本打算明天写的,可能要挪到周末了。
心急的朋友可以去我的github上 sidebar分支看,就是在本文的基础上,组合一个侧边栏自定义view,然后利用tinypinyin(https://github.com/promeg/tinypinyin),取数据源的拼音,然后利用拼音顺序排序数据源,set给adapter,set给侧边栏,监听侧边栏的item切换,在回调方法里,调用recyclerview的scrolltopositionwithoffset(int position, int offset) 方法,滑动recyclerview到指定位置~。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网