我有两个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
在第一个和最后一个位置添加了一个空项目,现在效果很好。在计算尺寸位置时,只需记住这些项目即可。