RecyclerView外包裹一个FrameLayout,通过adapter创建悬浮的Item,将其覆盖在RecyclerView上面,
再通过监听RecyclerView的滚动,动态改变悬浮item的translationY,实现悬浮。
floatRvItemContainer.showItemFloat = {
it % 8 == 0
}
floatRvItemContainer.observe()
package com.nevermore.floatbar
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import androidx.core.view.doOnNextLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
/**
* @author xuchuanting
* Create on 2021/4/14 17:17
*/
class FloatRvItemContainer : FrameLayout, FloatItemContract {
constructor(context: Context) : this(context, null)
constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super(
context,
attributeSet,
defStyleAttr
)
private var recyclerView: RecyclerView? = null
private var floatItemView: View? = null
private var viewHolder: RecyclerView.ViewHolder? = null
// fun showItemFloat(position: Int): Boolean
var showItemFloat: ((position: Int) -> Boolean)? = null
var adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = null
override fun onFinishInflate() {
super.onFinishInflate()
val view = getChildAt(0)
if (view is RecyclerView) {
recyclerView = view
}
}
var floatItemHeight = 0
private var currentFloatItemPoi = -1
fun observe() {
recyclerView?.let {
this.adapter = it.adapter
val firstFloatPosition = findNexFloatItemPosition(0)
ensureFloatItem(firstFloatPosition)
bindFloatItem(firstFloatPosition)
}
recyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager
if (layoutManager is LinearLayoutManager) {
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
if (showItemFloat(firstVisibleItemPosition)) {
updateFloatItem(firstVisibleItemPosition)
}
val nextItemPosition = firstVisibleItemPosition + 1
val itemCount = adapter?.itemCount ?: 0
if (nextItemPosition < itemCount) {
if (showItemFloat(nextItemPosition)) {
val preFloatItemPosition: Int =
findPreFloatItemPosition(firstVisibleItemPosition)
updateFloatItem(preFloatItemPosition)
val nextItemView = layoutManager.findViewByPosition(nextItemPosition)
nextItemView?.apply {
val top = nextItemView.top
if (top < floatItemHeight) {
onRequestFloatItemTranslationY((top - floatItemHeight).toFloat())
}
}
} else {
onRequestFloatItemTranslationY(0f)
}
}
}
}
})
}
private fun updateFloatItem(position: Int) {
if (currentFloatItemPoi != position) {
ensureFloatItem(position)
bindFloatItem(position)
currentFloatItemPoi = position
}
}
/**
* position 及之前该悬浮的item位置
*/
private fun findPreFloatItemPosition(position: Int): Int {
for (index in position downTo 0) {
if (showItemFloat(index)) {
return index
}
}
return 0
}
private fun findNexFloatItemPosition(position: Int): Int {
val itemCount = adapter?.itemCount ?: 0
for (index in position until itemCount) {
if (showItemFloat(index)) {
return index
}
}
return 0
}
private fun bindFloatItem(position: Int) {
adapter?.apply {
viewHolder?.let {
bindViewHolder(it, position)
}
}
}
private fun ensureFloatItem(position: Int) {
if (floatItemView == null) {
adapter?.let {
viewHolder =
it.createViewHolder(this@FloatRvItemContainer, it.getItemViewType(position))
floatItemView = viewHolder?.itemView?.apply {
this@apply.doOnNextLayout {
floatItemHeight = it.measuredHeight
}
}
addView(floatItemView)
}
}
}
override fun showItemFloat(position: Int): Boolean {
return showItemFloat?.invoke(position) ?: false
}
override fun onRequestFloatItemTranslationY(translationY: Float) {
floatItemView?.translationY = translationY
}
}
1月20日,360安全大脑监测发现,Win10系统出现严重漏洞,会导致电脑系统崩溃并显...
前两天公众号有个粉丝给我留言吐槽最近面试:四哥,年前我在公司受点委屈一冲动...
核心代码 scriptString.prototype.html = function(encode) { var replace =["#3...
字符 描述 \ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用...
转账 今天给大家聊聊智能合约账户之间的转账并给出了代码。 发起合约方账户 接受...
六、XML展望 任何一项新技术的产生都是有其需求背景的,XML的诞生是在HTML遇到不...
前言: 很多时候,因为数据统计,我们需要将数据库的数据导出到Excel等文件中,...
一 前言 对于正则表达式,相信很多人都知道,但是很多人的第一感觉就是难学,因...
我等卑微的码农,依旧还得唱着“你我皆凡人,生在人世间,终日奔波苦,一刻不得...
sequence文件存储格式 1.txt 纯文本格式,若干行记录。默认用字符编码存储 2.Seq...