網站首頁 編程語言 正文
方案
1.設置一個懸浮的視圖掛在recycleView頂部,隨著item的移動位置,懸浮標題自動跟隨移動或者是保持原地不動。
2.使用recyclerView的ItemDecoration,給指定的item設置不同的itemDecoration,并且跟隨item的移動而移動或者保持不變。
本文采用第二種方式實現,效果圖:
了解ItemDecoration
這是個接口,一共有六個方法:
public static abstract class ItemDecoration {
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn before the item views are drawn,
* and will thus appear underneath the views.
*
* @param c Canvas to draw into
* @param parent RecyclerView this ItemDecoration is drawing into
* @param state The current state of RecyclerView
*/
public void onDraw(Canvas c, RecyclerView parent, State state) {
onDraw(c, parent);
}
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn after the item views are drawn
* and will thus appear over the views.
*
* @param c Canvas to draw into
* @param parent RecyclerView this ItemDecoration is drawing into
* @param state The current state of RecyclerView.
*/
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
onDrawOver(c, parent);
}
/**
* Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
* the number of pixels that the item view should be inset by, similar to padding or margin.
* The default implementation sets the bounds of outRect to 0 and returns.
*
* <p>
* If this ItemDecoration does not affect the positioning of item views, it should set
* all four fields of <code>outRect</code> (left, top, right, bottom) to zero
* before returning.
*
* <p>
* If you need to access Adapter for additional data, you can call
* {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
* View.
*
* @param outRect Rect to receive the output.
* @param view The child view to decorate
* @param parent RecyclerView this ItemDecoration is decorating
* @param state The current state of RecyclerView.
*/
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
}
/**
* @deprecated
* Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}
*/
@Deprecated
public void onDrawOver(Canvas c, RecyclerView parent) {
}
/**
* @deprecated
* Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)}
*/
@Deprecated
public void onDraw(Canvas c, RecyclerView parent) {
}
/**
* @deprecated
* Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}
*/
@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}
}
其中有三個方法是@deprecated的,那么我們只需要看以下三個方法:
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);
}
第一個方法的意思是繪制分割線本身;
第二個方法是在item項目繪制完成之后進行的繪制操作(這個會覆蓋在item上面);
第三個方法是設置分割線的左間距,上間距,右間距,下間距,保存在outRect中。
如圖所示:
其中最底層黃色部分大小是getItemOffsets方法返回的itemDecoration的矩陣設置邊距寬度,onDraw方法根據設置的間距寬度來進行繪制黃色區域,其中棕紅色部分是onDrawOver方法覆蓋繪制在item上層的部分。
利用ItemDecoration來繪制懸浮標題欄
我們給每個需要title的item設置rect.top = titleHeight(標題欄高度);其他的間距可以先不考慮,不重要;
重寫onDraw方法,繪制我們的itemDecoration標題欄;
我們需要重寫onDrawOver方法,在滑動的時候去判斷,
1)如果頂部標題區域是在該標題的items范圍之內的滑動的話,那么我們需要覆蓋繪制一個處于recyclerView.getpaddingTop位置的title,這樣的話這個范圍內滑動就有一個懸停的標題欄;
2)如果頂部的標題欄區域恰好下面緊跟著下一個標題欄,那么繼續向上滑動的時候,需要下面的標題欄把上面的標題欄頂出界面之外。那么繪制的頂部標題欄的起始位置就是所處的item.bottom - titleHeight的位置。
使用以上三個步驟就可以做出一個流暢并且定制化很高的懸浮標題欄功能了。
代碼
class MyDecoration(context: Context): RecyclerView.ItemDecoration() {
var mPaint:Paint? = null
var mPaint2:Paint? = null
var mTextPaint:Paint? = null
var mTitleHeight:Int? = null
var mTitleHeight2:Int? = null
var mTitleTextSize:Float? = null
init {
mTitleHeight =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
30f,
context.getResources().getDisplayMetrics()
).toInt()
mTitleHeight2 =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
3f,
context.getResources().getDisplayMetrics()
).toInt()
mTitleTextSize =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
16f,
context.getResources().getDisplayMetrics()
)
mTextPaint = Paint()
mTextPaint?.let {
it.setTextSize(mTitleTextSize!!)
it.setAntiAlias(true)
it.setColor(Color.WHITE)
}
mPaint = Paint()
mPaint?.let {
it.setAntiAlias(true)
it.setColor(Color.RED)
}
mPaint2 = Paint()
mPaint2?.let {
it.setAntiAlias(true)
it.setColor(Color.BLUE)
}
}
/**
* recyclerView繪制onDraw -> item.onDraw -> onDrawOver
*/
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
for (index in 0 until parent.childCount) {
val childView = parent.getChildAt(index)
childView?.let {
val rect = Rect()
val position = parent.getChildAdapterPosition(it)
if (isTitleItem(position)) {
rect.top = childView.top - mTitleHeight!!
rect.bottom = childView.top
} else {
rect.top = childView.top - mTitleHeight2!!
rect.bottom = childView.top
}
rect.left = parent.paddingLeft
rect.right = parent.width - parent.paddingRight
if (isTitleItem(position)) {
mPaint?.let { it1 -> c.drawRect(rect, it1) }
mTextPaint?.let { it3 ->
c.drawText(
getTitleStr(position),
0f,
rect.top.toFloat() + (mTitleHeight?.div(2.00f)?:0f),
it3)}
} else {
mPaint2?.let { it1 -> c.drawRect(rect, it1) }
}
}
}
}
/**
* recyclerView繪制onDraw -> item.onDraw -> onDrawOver
* 繪制覆蓋在item上面的分割線效果
*/
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
val childView = parent.getChildAt(0)
var nextView:View? = null;
if (1 < parent.childCount) {
nextView = parent.getChildAt(1)
}
childView?.let {
val rect = Rect()
val position = parent.getChildAdapterPosition(it)
mTitleHeight?.let { height ->
if (nextView != null
&& it.bottom - height < parent.paddingTop
&& isTitleItem(parent.getChildAdapterPosition(nextView))
&& !isSameTitle(parent.getChildAdapterPosition(nextView),position)) {
rect.top = it.bottom - height
rect.bottom = it.bottom
} else {
rect.top = parent.paddingTop
rect.bottom = rect.top + height
}
}
rect.left = parent.paddingLeft
rect.right = parent.width - parent.paddingRight
mPaint?.let { it1 -> c.drawRect(rect, it1) }
mTextPaint?.let { it3 ->
c.drawText(
getTitleStr(position),
0f,
rect.top + (mTitleHeight?.div(2.00f)?:0f),
it3)}
}
}
/**
* 用于設置item周圍的偏移量的,類似于設置padding喝margin效果,
* 空出的效果用于繪制分割線
*/
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val position:Int = parent.getChildAdapterPosition(view)
if (position % 4 == 0) {
outRect.top = mTitleHeight!!
} else{
outRect.top = mTitleHeight2!!
}
}
fun isTitleItem(position: Int):Boolean {
return position % 4 == 0
}
fun getTitleStr(position: Int):String {
return "標題:${position / 4}"
}
fun isSameTitle(position1: Int,position2: Int):Boolean {
return (position1 / 4) == (position2 / 4)
}
}
原文鏈接:https://blog.csdn.net/u012345683/article/details/122816021
相關推薦
- 2022-05-25 pytorch?hook?鉤子函數的用法_python
- 2022-10-01 如何使用draw.io插件在vscode中一體化導出高質量圖片_python
- 2022-09-08 pandas實現datetime64與unix時間戳互轉_python
- 2023-07-05 go gorm想要查詢數據按照where in中的數據進行排序
- 2022-12-04 Flutter狀態管理Provider的使用示例詳解_Android
- 2022-02-23 Proxy error Could not proxy request錯誤解決
- 2022-03-18 C語言計算字符串最后一個單詞的長度_C 語言
- 2022-05-26 flutter實現底部抽屜效果_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支