android - 为 RecyclerView 中一定数量的可见项目调用 OnScrollListener
问题描述
我在回收站视图底部使用圆形页面指示器作为ItemDecoration ,并使用GridLayoutManager并将方向设置为 Horizo ntal。目前,当用户从左向右移动项目时,指示器会改变其位置,反之亦然。但是当用户滚动时,当屏幕上的总可见项目(此处为 6)发生偏移时,我需要更改页面指示器。因此,指标的总数会减少。
似乎RecyclerView.OnScrollListener将被放置来处理屏幕偏移。
bindingView.listPaymentType.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
Log.i("listPaymentType","onScrolled")
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
Log.i("listPaymentType","onScrollStateChanged")
super.onScrollStateChanged(recyclerView, newState)
}
})
我为这里的所有东西编写的代码。
itemDecor = CirclePagerIndicatorDecoration()
//bindingView.listPaymentType.addItemDecoration(itemDecor)
viewModel.paymentList.observe(this, Observer {
var layoutManager = GridLayoutManager(activity, 2,
GridLayoutManager.HORIZONTAL, false)
bindingView.listPaymentType.removeItemDecorations()
when {
it.size == 4 -> {
layoutManager.spanCount = 1
bindingView.listPaymentType.addItemDecoration(itemDecor)
}
it.size > 4 -> {
layoutManager.spanCount = 2
bindingView.listPaymentType.addItemDecoration(itemDecor)
}
else -> {
layoutManager.spanCount = 1
}
}
bindingView.listPaymentType.layoutManager = layoutManager
bindingView.listPaymentType.adapter = adapter
adapter.update(it as ArrayList<PaymentMethod>)
if (it.isNotEmpty()) {
adapter.selectedItem(it[0])
}
})
CirclePagerIndicator装饰如下:
class CirclePagerIndicatorDecoration : RecyclerView.ItemDecoration() {
private val colorActive = 0xFF545455.toInt()
private val colorInactive = 0x33000000
/**
* Height of the space the indicator takes up at the bottom of the view.
*/
private val mIndicatorHeight = (DP * 12).toInt()
/**
* Indicator stroke width.
*/
private val mIndicatorStrokeWidth = DP * 4
/**
* Indicator width.
*/
private val mIndicatorItemLength = DP * 2
/**
* Padding between indicators.
*/
private val mIndicatorItemPadding = DP * 8
/**
* Some more natural animation interpolation
*/
private val mInterpolator = AccelerateDecelerateInterpolator()
private val mPaint = Paint()
init {
mPaint.apply {
strokeWidth = mIndicatorStrokeWidth
style = Paint.Style.STROKE
isAntiAlias = true
}
}
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)
val itemCount = parent.adapter?.itemCount?.div(COUNT_DIVIDER)?.toInt() ?: 0
// center horizontally, calculate width and subtract half from center
val totalLength = mIndicatorItemLength * itemCount
val paddingBetweenItems = Math.max(0, itemCount - 1) * mIndicatorItemPadding
val indicatorTotalWidth = totalLength + paddingBetweenItems
val indicatorStartX = (parent.width - indicatorTotalWidth) / 2f
// center vertically in the allotted space
val indicatorPosY = parent.height - mIndicatorHeight / 2f
drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount)
// find active page (which should be highlighted)
(parent.layoutManager as? LinearLayoutManager)?.let { layoutManager ->
val activePosition = layoutManager.findFirstVisibleItemPosition()
if (activePosition == RecyclerView.NO_POSITION) {
return
}
// find offset of active page (if the user is scrolling)
layoutManager.findViewByPosition(activePosition)?.let { activeChild ->
val left = activeChild.left
val width = activeChild.width
// on swipe the active item will be positioned from [-width, 0]
// interpolate offset for smooth animation
val progress = mInterpolator.getInterpolation(left * -1 / width.toFloat())
drawHighlights(c, indicatorStartX, indicatorPosY, activePosition, progress)
}
}
}
private fun drawInactiveIndicators(c: Canvas, indicatorStartX: Float, indicatorPosY: Float, itemCount: Int) {
mPaint.color = colorInactive
// width of item indicator including padding
val itemWidth = mIndicatorItemLength + mIndicatorItemPadding
var start = indicatorStartX
for (i in 0 until itemCount) {
c.drawCircle(start, indicatorPosY, mIndicatorItemLength / 2f, mPaint)
start += itemWidth
}
}
private fun drawHighlights(
c: Canvas, indicatorStartX: Float, indicatorPosY: Float,
highlightPosition: Int, progress: Float
) {
mPaint.color = colorActive
// width of item indicator including padding
val itemWidth = mIndicatorItemLength + mIndicatorItemPadding
val radius = mIndicatorItemLength / SCALE
if (progress == 0f) {
// no swipe, draw a normal indicator
val highlightStart = indicatorStartX + itemWidth * highlightPosition
c.drawCircle(highlightStart, indicatorPosY, radius, mPaint)
} else {
val highlightStart = indicatorStartX + itemWidth * highlightPosition
// calculate partial highlight
val partialLength = mIndicatorItemLength * progress + (mIndicatorItemPadding * progress)
c.drawCircle(highlightStart + partialLength, indicatorPosY, radius, mPaint)
}
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
outRect.bottom = mIndicatorHeight
}
companion object {
private val DP = Resources.getSystem().displayMetrics.density
private const val COUNT_DIVIDER: Float = 1.4f
private const val SCALE: Float = 1.1f
}
}
解决方案
推荐阅读
- android - 在 Android 中备份 SQLite 数据库
- zend-framework - 在 Zend 1.11 的 Bootstrap.php 文件中获取模块、控制器和动作名称
- wordpress - 添加菜单作为最后一项 - Wordpress
- networking - 如何塑造输入数据以训练自动编码器
- sql-server - 多可用区环境中的 DEFAULT_DATABASE
- javascript - 附加事件处理程序和每个函数
- angular - 打字稿传单标记自定义属性
- r - R plotly plot_ly 函数:当我在项目中调用 plotly 时,不会出现轴标题
- import - Dspace 导入器找不到集合
- sql - 加入发货后订单数量翻倍