国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android RecyclerView打造懸浮效果的實現代碼

2019-10-22 18:25:13
字體:
來源:轉載
供稿:網友

本文介紹了Android RecyclerView懸浮效果,分享給大家,具體如下:

先看個效果

Android,RecyclerView懸浮,懸浮效果,懸浮

這是一個City列表,每個City都有所屬的Province,需要在滑動的時候,將對應的Province懸浮在頂部。懸浮頂部的Province需要根據列表的滑動而適當改變位置,實現“頂上去”的效果。

實現思路:

  1. 利用RecyclerView.ItemDecoration繪制Province(就像繪制分割線一樣)
  2. 同一組的City,只繪制一個Province
  3. 計算偏移,將當前Province固定在頂部
  4. 根據列表滑動,實現偏移效果

ItemDecoration

既然是利用RecyclerView.ItemDecoration實現的懸浮效果,那么有必要了解下它。

ItemDecoration字面意思:Item的裝飾。是的!是裝飾!不只是畫分割線。

其實ItemDecoration的功能非常強大,而我們平時只是用它來實現分割線的效果(至少我是這樣)。因此,可能很多同學認為ItemDecoration就是用來繪制分割線的。其實不然,ItemDecoration的功能遠不止是分割線的繪制。

先看下RecyclerView.ItemDecoration的源碼(部分):

public static abstract class ItemDecoration { ... public void onDraw(Canvas c, RecyclerView parent, State state) {  onDraw(c, parent); } public void onDrawOver(Canvas c, RecyclerView parent, State state) {  onDrawOver(c, parent); } public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {  getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),    parent); }}

里面是我們常用的三個方法:

  1. getItemOffsets:通過Rect為每個Item設置偏移,用于繪制Decoration。
  2. onDraw:通過該方法,在Canvas上繪制內容,在繪制Item之前調用。(如果沒有通過getItemOffsets設置偏移的話,Item的內容會將其覆蓋)
  3. onDrawOver:通過該方法,在Canvas上繪制內容,在Item之后調用。(畫的內容會覆蓋在item的上層)

RecyclerView 的背景、onDraw繪制的內容、Item、onDrawOver繪制的內容,各層級關系如下:

Android,RecyclerView懸浮,懸浮效果,懸浮

層級關系

繪制分割線

先看看一般的分割線繪制。

定義分割線高度

private int mHeight = 5; //分割線高度

通過getItemOffsets預留空間

@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int position = parent.getChildAdapterPosition(view); if (position != 0) {  //第一個item預留空間  outRect.top = mHeight; }}

然后在onDraw中繪制

@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); final int left = parent.getLeft(); final int right = parent.getRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) {  final View childView = parent.getChildAt(i);  final int bottom = childView.getTop();  final int top = bottom - mHeight;  c.drawRect(left, top, right, bottom, mPaint); }}

獲取當前RecyclerView的Item數量,遍歷每個Item。在對應的位置繪制一個高度為mHeight的矩形 ,從而實現分割線的效果。

Android,RecyclerView懸浮,懸浮效果,懸浮

(詳情代碼見底部鏈接)

打造懸浮效果

這是一個城市列表,根據省份分組,相同的城市只會顯示一個省份。滾動城市列表時,省份會懸浮在頂部。效果如下:

Android,RecyclerView懸浮,懸浮效果,懸浮

實現

由于需要懸浮效果,所以需要在onDrawOver中繪制分組。

定義一個interface,根據position通過接口方法getGroupName獲取當前省名(由Activity實現)

public interface GroupListener { String getGroupName(int position);}

創建StickyDecoration繼承RecyclerView.ItemDecoration

定義isFirstInGroup方法。根據前一個省份,判斷當前是否為新的省份

//判斷是不是組中的第一個位置//根據前一個組名,判斷當前是否為新的組private boolean isFirstInGroup(int pos) { if (pos == 0) { return true; } else { String prevGroupId = getGroupName(pos - 1); String groupId = getGroupName(pos); return !TextUtils.equals(prevGroupId, groupId); }}

通過position,對比上一個省份名稱,判斷當前省是否為第一個

重寫getItemOffsets方法,為懸浮欄預留空間

@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int pos = parent.getChildAdapterPosition(view); String groupId = getGroupName(pos); if (groupId == null) return; //只有是同一組的第一個才顯示懸浮欄 if (pos == 0 || isFirstInGroup(pos)) { outRect.top = mGroupHeight; }}

只有第一個Item或者新的省份才為懸浮欄預留空間

重寫onDrawOver方法(重點)

@Overridepublic void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {super.onDrawOver(c, parent, state);final int itemCount = state.getItemCount();final int childCount = parent.getChildCount();final int left = parent.getLeft() + parent.getPaddingLeft();final int right = parent.getRight() - parent.getPaddingRight();String preGroupName;  //標記上一個item對應的GroupString currentGroupName = null;  //當前item對應的Groupfor (int i = 0; i < childCount; i++) { View view = parent.getChildAt(i); int position = parent.getChildAdapterPosition(view); preGroupName = currentGroupName; currentGroupName = getGroupName(position); if (currentGroupName == null || TextUtils.equals(currentGroupName, preGroupName))  continue; int viewBottom = view.getBottom(); float top = Math.max(mGroupHeight, view.getTop());//top 決定當前頂部第一個懸浮Group的位置 if (position + 1 < itemCount) {  //獲取下個GroupName  String nextGroupName = getGroupName(position + 1);  //下一組的第一個View接近頭部  if (!currentGroupName.equals(nextGroupName) && viewBottom < top) {   top = viewBottom;  } } //根據top繪制group c.drawRect(left, top - mGroupHeight, right, top, mGroutPaint); Paint.FontMetrics fm = mTextPaint.getFontMetrics(); //文字豎直居中顯示 float baseLine = top - (mGroupHeight - (fm.bottom - fm.top)) / 2 - fm.bottom; c.drawText(currentGroupName, left + mLeftMargin, baseLine, mTextPaint); }}

通過變量preGroupId和currentGroupId來保存當前分組名和上一個分組名。當前Item與上一個Item為同一個分組時,跳過該Item的繪制。

其中代碼:

float top = Math.max(mGroupHeight, view.getTop());

根據當前Item的位置確定繪制分組的位置。top將在mGroupHeight和view.getTop()中取最大值,也就是說top將不會小于mGroupHeight,這樣就能實現吸頂效果。

其中代碼:

if (!currentGroupName.equals(nextGroupName) && viewBottom < top) {  top = viewBottom; }

當下個分組的頂部(當前Item的底部viewBottom可近似認為下個Item的頂部)距離RecyclerView頂部小于top時,偏移當前分組位置。實現下一組上滑時候,當前分組上移;上一組下滑的時候,當前分組下移。
最后計算baseLine,并繪制背景和文字。

到目前為止,一個帶有懸浮功能的列表就實現了。

(詳細代碼見底部鏈接)

Android,RecyclerView懸浮,懸浮效果,懸浮

進階

當我們利用ItemDecoration實現文字的懸浮的時候,是不是還可以搞點事情~ ~我有個大膽的想法
只有文字的懸浮怎么行!我還希望可以再來個icon?再來幾個TextView?來個自定義布局?那就來個自定義布局吧。

實現

實現的原理跟上面一樣,由于需要自定義布局,所以需要在接口中添加一個獲取View的方法。

定義PowerGroupListener

public interface PowerGroupListener { String getGroupName(int position); View getGroupView(int position);}

相比之前,多了個getGroupView方法,用來獲取View。

在onDrawOver中繪制

@Overridepublic void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { ... for (int i = 0; i < childCount; i++) {  ...  //根據position獲取View  View groupView = mGroupListener.getGroupView(position);  if (groupView == null) return;  ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mGroupHeight);groupView.setLayoutParams(layoutParams);  groupView.setDrawingCacheEnabled(true);  groupView.measure(    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));  //指定高度、寬度的groupView  groupView.layout(0, 0, right, mGroupHeight);  groupView.buildDrawingCache();  Bitmap bitmap = groupView.getDrawingCache();  c.drawBitmap(bitmap, left, top - mGroupHeight, null); }}

在原來的基礎上做了點修改,通過接口的getGroupView方法獲取需要繪制的分組View,將得到的View繪制到指定位置。

效果:

Android,RecyclerView懸浮,懸浮效果,懸浮

(詳細代碼見底部鏈接)

源碼鏈接

已封裝成庫,歡迎來提Issues

repositories { jcenter()// If not already there}dependencies { compile 'com.gavin.com.library:stickyDecoration:1.0.2'}

詳細用法級源碼請看Github

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 方城县| 南京市| 南宁市| 牙克石市| 崇文区| 阿坝| 加查县| 沁源县| 正宁县| 新密市| 东港市| 东方市| 鄂温| 兴和县| 延津县| 湘潭县| 钟祥市| 铜陵市| 辽阳县| 根河市| 老河口市| 重庆市| 泾川县| 新蔡县| 晋州市| 郓城县| 晴隆县| 通河县| 达州市| 健康| 宁海县| 平江县| 水城县| 牟定县| 繁峙县| 福州市| 根河市| 安吉县| 保德县| 天镇县| 河东区|