So this is pretty tricky. The closest thing I have found to get this working is a modified version of this answer. Where I make the last item the same height as the view I want to be full width and invisible. Then I add an itemdecoration and draw it where the last item in the list should be visible like this:
class StickyDecoration (private val stickyView: View) : ItemDecoration() {
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
// layout basically just gets drawn on the reserved space on top of the first view
stickyView.layout(parent.left, 0, parent.right, stickyView.measuredHeight)
for (i in 0 until parent.childCount) {
val view: View = parent.getChildAt(i)
if (parent.getChildAdapterPosition(view) == parent.childCount - 1) {
c.save()
val rectf = Rect()
view.getGlobalVisibleRect(rectf)
c.translate(0f, (rectf.top).toFloat())
stickyView.draw(c)
c.restore()
break
}
}
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
outRect.setEmpty()
}
}
The problem with this approach is when items in the recyclerview above the last one disappears from view, then the value of rectf.top
or view.top
or any measurement I can think of make a leap and displaces the last item.
Does anyone know of a way to add a full width last item or footer to a recyclerview with a StaggeredGridLayoutManager? I know it works with Gridlayout but its not an option in my case.
Or if you know of a value which gets to correct position of the last item on the screen without any jump in values?
EDIT:
More details of what I'd like to achieve.
It should be a StaggeredGridLayout with a footer below the last item, which is full width and scrolls with the rest of the content.
To make a full width footer in a recyclerView using StaggeredGridLayoutManager you can do the following. Create a custom ItemDecoration:
class FooterDecoration (private val footerView: View) : ItemDecoration() {
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
footerView.layout(parent.left, 0, parent.right, footerView.measuredHeight)
val count = parent.adapter!!.itemCount
val view: View = parent.getChildAt(parent.childCount - 1)
if (parent.getChildAdapterPosition(view) == count - 1) {
c.save()
val rect = Rect()
view.getGlobalVisibleRect(rect)
c.translate(0f, (rect.top).toFloat())
footerView.draw(c)
c.restore()
}
}
}
Then in your recyclerView inflate the view you want to use and add it as an item decoration:
recyclerView.apply {
val footerView: View = LayoutInflater.from(context).inflate(R.layout.item_footer_placeholder, this, false)
val measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
footerView.measure(measureSpec, measureSpec)
addItemDecoration(ServicesFooterDecoration(footerView))
}