国产探花免费观看_亚洲丰满少妇自慰呻吟_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開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 高淳县| 融水| 永仁县| 湘西| 临夏县| 淮安市| 通榆县| 微博| 布拖县| 太康县| 香港 | 息烽县| 佳木斯市| 聂拉木县| 湖北省| 吉隆县| 改则县| 东兴市| 陇南市| 宣威市| 香河县| 宁乡县| 桐梓县| 汕头市| 灌南县| 轮台县| 乌鲁木齐县| 剑阁县| 南江县| 虞城县| 廊坊市| 仁怀市| 刚察县| 洪洞县| 恩平市| 土默特左旗| 两当县| 淮北市| 淳安县| 隆林| 苏尼特左旗|