安卓当下最流行的吸顶效果的实现(下)

移动开发 Android
今天接着上次让我使用ItemDecoration来完成可推动的悬浮导航栏的效果。

接上文

***步:首先我们来写一个类,它起标记的作用,来放每一个item的对应的悬浮栏的字符串

  1. public class NameBean {   
  2.     String name;   
  3.    
  4.     public String getName() {   
  5.         return name;   
  6.     }   
  7.    
  8.     public void setName(String name) {   
  9.         this.name = name;   
  10.     }   

 

第二步:自定义一个SectionDecoration 类 继承 RecyclerView的ItemDecoration

  1. public class SectionDecoration extends RecyclerView.ItemDecoration {   
  2.     private static final String TAG = "SectionDecoration";   
  3.    
  4.     private List<NameBean> dataList;   
  5.    
  6.     private DecorationCallback callback;   
  7.     private TextPaint textPaint;   
  8.     private Paint paint;   
  9.     private int topGap;   
  10.     private int alignBottom;   
  11.     private Paint.FontMetrics fontMetrics;   
  12.    
  13.    
  14.     public SectionDecoration(List<NameBean> dataList, Context context, DecorationCallback decorationCallback) {   
  15.         Resources res = context.getResources();   
  16.         this.dataList = dataList;   
  17.         this.callback = decorationCallback;   
  18.         //设置悬浮栏的画笔---paint   
  19.         paint = new Paint();   
  20.         paint.setColor(res.getColor(R.color.colorGray));   
  21.    
  22.         //设置悬浮栏中文本的画笔   
  23.         textPaint = new TextPaint();   
  24.         textPaint.setAntiAlias(true);   
  25.         textPaint.setTextSize(DensityUtil.dip2px(context, 14));   
  26.         textPaint.setColor(Color.DKGRAY);   
  27.         textPaint.setTextAlign(Paint.Align.LEFT);   
  28.         fontMetrics = new Paint.FontMetrics();   
  29.         //决定悬浮栏的高度等   
  30.         topGap = res.getDimensionPixelSize(R.dimen.sectioned_top);   
  31.         //决定文本的显示位置等   
  32.         alignBottom = res.getDimensionPixelSize(R.dimen.sectioned_alignBottom);   
  33.     }   
  34.    
  35.     @Override   
  36.     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {   
  37.         super.getItemOffsets(outRect, view, parent, state);   
  38.         int pos = parent.getChildAdapterPosition(view);   
  39.         Log.i(TAG, "getItemOffsets:" + pos);   
  40.         String groupId = callback.getGroupId(pos);   
  41.         if (groupId.equals("-1")) return;   
  42.         //只有是同一组的***个才显示悬浮栏   
  43.         if (pos == 0 || isFirstInGroup(pos)) {   
  44.             outRect.top = topGap;   
  45.             if (dataList.get(pos).getName() == "") {   
  46.                 outRect.top = 0;   
  47.             }   
  48.         } else {   
  49.             outRect.top = 0;   
  50.         }   
  51.     }   
  52.    
  53.     @Override   
  54.     public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {   
  55.         super.onDraw(c, parent, state);   
  56.         int left = parent.getPaddingLeft();   
  57.         int right = parent.getWidth() - parent.getPaddingRight();   
  58.         int childCount = parent.getChildCount();   
  59.         for (int i = 0; i < childCount; i++) {   
  60.             View view = parent.getChildAt(i);   
  61.             int position = parent.getChildAdapterPosition(view);   
  62.             String groupId = callback.getGroupId(position);   
  63.             if (groupId.equals("-1")) return;   
  64.             String textLine = callback.getGroupFirstLine(position).toUpperCase();   
  65.             if (textLine == "") {   
  66.                 float top = view.getTop();   
  67.                 float bottom = view.getTop();   
  68.                 c.drawRect(lefttopright, bottom, paint);   
  69.                 return;   
  70.             } else {   
  71.                 if (position == 0 || isFirstInGroup(position)) {   
  72.                     float top = view.getTop() - topGap;   
  73.                     float bottom = view.getTop();   
  74.                     //绘制悬浮栏   
  75.                     c.drawRect(lefttop - topGap, right, bottom, paint);   
  76.                     //绘制文本   
  77.                     c.drawText(textLine, left, bottom, textPaint);   
  78.                 }   
  79.             }   
  80.         }   
  81.     }   
  82.    
  83.     @Override   
  84.     public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {   
  85.         super.onDrawOver(c, parent, state);   
  86.         int itemCount = state.getItemCount();   
  87.         int childCount = parent.getChildCount();   
  88.         int left = parent.getPaddingLeft();   
  89.         int right = parent.getWidth() - parent.getPaddingRight();   
  90.         float lineHeight = textPaint.getTextSize() + fontMetrics.descent;   
  91.    
  92.         String preGroupId = "";   
  93.         String groupId = "-1";   
  94.         for (int i = 0; i < childCount; i++) {   
  95.             View view = parent.getChildAt(i);   
  96.             int position = parent.getChildAdapterPosition(view);   
  97.    
  98.             preGroupId = groupId;   
  99.             groupId = callback.getGroupId(position);   
  100.             if (groupId.equals("-1") || groupId.equals(preGroupId)) continue;   
  101.    
  102.             String textLine = callback.getGroupFirstLine(position).toUpperCase();   
  103.             if (TextUtils.isEmpty(textLine)) continue;   
  104.    
  105.             int viewBottom = view.getBottom();   
  106.             float textY = Math.max(topGap, view.getTop());   
  107.             //下一个和当前不一样移动当前   
  108.             if (position + 1 < itemCount) {   
  109.                 String nextGroupId = callback.getGroupId(position + 1);   
  110.                 //组内***一个view进入了header   
  111.                 if (nextGroupId != groupId && viewBottom < textY) {   
  112.                     textY = viewBottom;   
  113.                 }   
  114.             }   
  115.             //textY - topGap决定了悬浮栏绘制的高度和位置   
  116.             c.drawRect(left, textY - topGap, right, textY, paint);   
  117.             //left+2*alignBottom 决定了文本往左偏移的多少(加-->向左移)   
  118.             //textY-alignBottom  决定了文本往右偏移的多少  (减-->向上移)   
  119.             c.drawText(textLine, left + 2 * alignBottom, textY - alignBottom, textPaint);   
  120.         }   
  121.     }   
  122.    
  123.    
  124.     /** 
  125.      * 判断是不是组中的***个位置 
  126.      * 
  127.      * @param pos 
  128.      * @return 
  129.      */   
  130.     private boolean isFirstInGroup(int pos) {   
  131.         if (pos == 0) {   
  132.             return true;   
  133.         } else {   
  134.             // 因为是根据 字符串内容的相同与否 来判断是不是同意组的,所以此处的标记id 要是String类型   
  135.             // 如果你只是做联系人列表,悬浮框里显示的只是一个字母,则标记id直接用 int 类型就行了   
  136.             String prevGroupId = callback.getGroupId(pos - 1);   
  137.             String groupId = callback.getGroupId(pos);   
  138.             //判断前一个字符串 与 当前字符串 是否相同   
  139.             if (prevGroupId.equals(groupId)) {   
  140.                 return false;   
  141.             } else {   
  142.                 return true;   
  143.             }   
  144.         }   
  145.     }   
  146.    
  147.     //定义一个借口方便外界的调用   
  148.     interface DecorationCallback {   
  149.         String getGroupId(int position);   
  150.    
  151.         String getGroupFirstLine(int position);   
  152.     }   

 

第三步:在向list集合中先把每一个item的 起“标记”作用的字符串都加进去

  1. setPullAction(comingslist); 
  1. private void setPullAction(List<WaitMVBean.DataBean.ComingBean> comingslist) {   
  2.         dataList = new ArrayList<>();   
  3.    
  4.         for (int i = 0; i < comingslist.size(); i++) {   
  5.             NameBean nameBean = new NameBean();   
  6.             String name0 = comingslist.get(i).getComingTitle();   
  7.             nameBean.setName(name0);   
  8.             dataList.add(nameBean);   
  9.         }   
  10.     } 

 

第四步:在setAdapter() 前,为RecyclerView添加ItemDecoration:

  1. recyclerView.addItemDecoration(new SectionDecoration(dataList,mContext, new SectionDecoration.DecorationCallback() {   
  2.                //返回标记id (即每一项对应的标志性的字符串)   
  3.                 @Override   
  4.                 public String getGroupId(int position) {   
  5.                     if(dataList.get(position).getName()!=null) {   
  6.                         return dataList.get(position).getName();   
  7.                     }   
  8.                     return "-1";   
  9.                 }   
  10.    
  11.                 //获取同组中的***个内容   
  12.                 @Override   
  13.                 public String getGroupFirstLine(int position) {   
  14.                     if(dataList.get(position).getName()!=null) {   
  15.                         return dataList.get(position).getName();   
  16.                     }   
  17.                     return "";   
  18.                 }   
  19.             })); 

 

这样就完成了~

再看一眼最终效果感受一下:

责任编辑:庞桂玉 来源: 安卓开发精选
相关推荐

2017-01-13 11:10:41

Android吸顶效果开发

2022-07-28 14:33:32

webviewweb页面

2023-10-11 08:14:43

iPhoneTabs标签页

2020-08-19 10:22:45

CIOIT试点项目技术

2011-05-03 10:40:58

Ubuntu 11.0应用

2018-01-31 11:10:21

安卓操作系统手机屏幕

2014-02-19 10:34:48

JavaScript代码规范

2014-02-04 19:44:23

编程语言开发

2021-07-13 06:51:16

H5web开发吸顶

2011-03-21 13:01:10

2012-05-23 14:36:53

柯基病毒

2011-01-04 18:04:49

PHP

2010-07-20 09:49:07

分布式文件系统

2013-03-20 10:20:00

2017-06-27 14:02:09

前端框架Bootstrap

2021-07-28 14:25:01

编程语言开发JavaScript

2023-03-31 11:21:10

网络协议LoRaWAN

2018-03-13 09:34:30

人工智能编程语言Python

2016-10-21 17:13:16

开发Java

2017-07-14 14:50:00

架构框架前端
点赞
收藏

51CTO技术栈公众号