我RecyclerViews
有两个,ItemDecoration
每个两个,为第一个和最后一个项目添加一个固定的偏移量。
StartOffsetItemDecoration.kt
class StartOffsetItemDecoration : RecyclerView.ItemDecoration {
private var mOffsetPx: Int = 0
private var mOffsetDrawable: Drawable? = null
private var mOrientation: Int = 0
/**
* Constructor that takes in the size of the offset to be added to the
* start of the RecyclerView.
*
* @param offsetPx The size of the offset to be added to the start of the
* RecyclerView in pixels
*/
constructor(offsetPx: Int) {
mOffsetPx = offsetPx
}
/**
* Constructor that takes in a {@link Drawable} to be drawn at the start of
* the RecyclerView.
*
* @param offsetDrawable The {@code Drawable} to be added to the start of
* the RecyclerView
*/
constructor(offsetDrawable: Drawable) {
mOffsetDrawable = offsetDrawable
}
/**
* Determines the size and location of the offset to be added to the start
* of the RecyclerView.
*
* @param outRect The [Rect] of offsets to be added around the child view
* @param view The child view to be decorated with an offset
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
if (parent.getChildAdapterPosition(view) > 0) {
return
}
mOrientation = (parent.layoutManager as LinearLayoutManager).orientation
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
if (mOffsetPx > 0) {
outRect.left = mOffsetPx
} else if (mOffsetDrawable != null) {
outRect.left = mOffsetDrawable!!.intrinsicWidth
}
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
if (mOffsetPx > 0) {
outRect.top = mOffsetPx
} else if (mOffsetDrawable != null) {
outRect.top = mOffsetDrawable!!.intrinsicHeight
}
}
}
/**
* Draws horizontal or vertical offset onto the start of the parent
* RecyclerView.
*
* @param c The [Canvas] onto which an offset will be drawn
* @param parent The RecyclerView onto which an offset is being added
* @param state The current RecyclerView.State of the RecyclerView
*/
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
if (mOffsetDrawable == null) {
return
}
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
drawOffsetHorizontal(c, parent)
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
drawOffsetVertical(c, parent)
}
}
private fun drawOffsetHorizontal(canvas: Canvas, parent: RecyclerView) {
val parentTop = parent.paddingTop
val parentBottom = parent.height - parent.paddingBottom
val parentLeft = parent.paddingLeft
val offsetDrawableRight = parentLeft + mOffsetDrawable!!.intrinsicWidth
mOffsetDrawable?.setBounds(parentLeft, parentTop, offsetDrawableRight, parentBottom)
mOffsetDrawable?.draw(canvas)
}
private fun drawOffsetVertical(canvas: Canvas, parent: RecyclerView) {
val parentLeft = parent.paddingLeft
val parentRight = parent.width - parent.paddingRight
val parentTop = parent.paddingTop
val offsetDrawableBottom = parentTop + mOffsetDrawable!!.intrinsicHeight
mOffsetDrawable?.setBounds(parentLeft, parentTop, parentRight, offsetDrawableBottom)
mOffsetDrawable?.draw(canvas)
}
}
EndOffsetItemDecoration.kt
class EndOffsetItemDecoration: RecyclerView.ItemDecoration {
private var mOffsetPx: Int = 0
private var mOffsetDrawable: Drawable? = null
private var mOrientation: Int = 0
/**
* Constructor that takes in the size of the offset to be added to the
* start of the RecyclerView.
*
* @param offsetPx The size of the offset to be added to the start of the
* RecyclerView in pixels
*/
constructor(offsetPx: Int) {
mOffsetPx = offsetPx
}
/**
* Constructor that takes in a {@link Drawable} to be drawn at the start of
* the RecyclerView.
*
* @param offsetDrawable The {@code Drawable} to be added to the start of
* the RecyclerView
*/
constructor(offsetDrawable: Drawable) {
mOffsetDrawable = offsetDrawable
}
/**
* Determines the size and location of the offset to be added to the end
* of the RecyclerView.
*
* @param outRect The [Rect] of offsets to be added around the child view
* @param view The child view to be decorated with an offset
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
val itemCount = state.itemCount
if (parent.getChildAdapterPosition(view) != itemCount - 1) {
return
}
mOrientation = (parent.layoutManager as LinearLayoutManager).orientation
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
if (mOffsetPx > 0) {
outRect.right = mOffsetPx
} else if (mOffsetDrawable != null) {
outRect.right = mOffsetDrawable!!.intrinsicWidth
}
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
if (mOffsetPx > 0) {
outRect.bottom = mOffsetPx
} else if (mOffsetDrawable != null) {
outRect.bottom = mOffsetDrawable!!.intrinsicHeight
}
}
}
/**
* Draws horizontal or vertical offset onto the end of the parent
* RecyclerView.
*
* @param c The [Canvas] onto which an offset will be drawn
* @param parent The RecyclerView onto which an offset is being added
* @param state The current RecyclerView.State of the RecyclerView
*/
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
if (mOffsetDrawable == null) {
return
}
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
drawOffsetHorizontal(c, parent)
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
drawOffsetVertical(c, parent)
}
}
private fun drawOffsetHorizontal(canvas: Canvas, parent: RecyclerView) {
val parentTop = parent.paddingTop
val parentBottom = parent.height - parent.paddingBottom
val lastChild = parent.getChildAt(parent.childCount - 1)
val lastChildLayoutParams = lastChild.layoutParams as RecyclerView.LayoutParams
val offsetDrawableLeft = lastChild.right + lastChildLayoutParams.rightMargin
val offsetDrawableRight = offsetDrawableLeft + mOffsetDrawable!!.intrinsicWidth
mOffsetDrawable?.setBounds(offsetDrawableLeft, parentTop, offsetDrawableRight, parentBottom)
mOffsetDrawable?.draw(canvas)
}
private fun drawOffsetVertical(canvas: Canvas, parent: RecyclerView) {
val parentLeft = parent.paddingLeft
val parentRight = parent.width - parent.paddingRight
val lastChild = parent.getChildAt(parent.childCount - 1)
val lastChildLayoutParams = lastChild.layoutParams as RecyclerView.LayoutParams
val offsetDrawableTop = lastChild.bottom + lastChildLayoutParams.bottomMargin
val offsetDrawableBottom = offsetDrawableTop + mOffsetDrawable!!.intrinsicHeight
mOffsetDrawable?.setBounds(parentLeft, offsetDrawableTop, parentRight, offsetDrawableBottom)
mOffsetDrawable?.draw(canvas)
}
}
我还在PagerSnapHelper
两者上都添加了一个,RecyclerViews
但它们似乎不适用于给定的偏移量。我想我可能缺少一些配置,或者可能PageSnapHelper
知道偏移量,以便它可以计算第一个和最后一个元素的正确捕捉。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_anomaly_solution_hours)
hours.layoutManager = LinearLayoutManager(
this@AnomalySolutionHoursActivity, LinearLayoutManager.VERTICAL, false
)
minutes.layoutManager = LinearLayoutManager(
this@AnomalySolutionHoursActivity, LinearLayoutManager.VERTICAL, false
)
hours.setHasFixedSize(true)
minutes.setHasFixedSize(true)
hours.addItemDecoration(StartOffsetItemDecoration(calculateOffset().toInt()))
hours.addItemDecoration(EndOffsetItemDecoration(calculateOffset().toInt()))
minutes.addItemDecoration(StartOffsetItemDecoration(calculateOffset().toInt()))
minutes.addItemDecoration(EndOffsetItemDecoration(calculateOffset().toInt()))
val hoursSnapHelper = PagerSnapHelper()
val minutesSnapHelper = PagerSnapHelper()
hours.adapter = TimeAdapter((0..10).toList().toTypedArray(), this@AnomalySolutionHoursActivity,
object: TimeAdapter.OnItemClickListener {
override fun onItemClick(unit: Int) {
}
})
hoursSnapHelper.attachToRecyclerView(hours)
minutes.adapter = TimeAdapter((0..60).toList().toTypedArray(), this@AnomalySolutionHoursActivity,
object: TimeAdapter.OnItemClickListener {
override fun onItemClick(unit: Int) {
}
})
minutesSnapHelper.attachToRecyclerView(minutes)
}
private fun calculateOffset(): Float {
val listHalfHeight = (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 250f, resources.displayMetrics)) / 2
val listItemHalfHeight = (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48f, resources.displayMetrics)) / 2
return listHalfHeight - listItemHalfHeight
}
}
有人能够使 PagerSnapHelper 与包含偏移量的 RecyclerView 一起工作吗?LinearSnapHelper 似乎比 PagerSnapHelper 工作得更好,但仍然无法捕捉第一个和最后一个项目。
谢谢!
更新
使两个列表高度都达到 500dp,但没有任何改变。
更新 2
在第一个和最后一个位置添加了一个空项目,现在它工作得很好。在计算尺寸的位置时,只需要记住这些项目。