Skip to content

Instantly share code, notes, and snippets.

@charlesmadere
Created November 14, 2017 19:36
Show Gist options
  • Save charlesmadere/0d1ba392e0a6f2c8eed5869df599c278 to your computer and use it in GitHub Desktop.
Save charlesmadere/0d1ba392e0a6f2c8eed5869df599c278 to your computer and use it in GitHub Desktop.
import android.graphics.Rect
import android.support.annotation.DimenRes
import android.support.annotation.Dimension
import android.support.v7.widget.GridLayoutManager
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.View
/**
* Use this class to easily add space between items in a RecyclerView. Just instantiate a new
* instance of the Builder class and you'll be good to go.
*/
abstract class SpaceItemDecoration internal constructor(
@Dimension protected val betweenSpacing: Int,
@Dimension protected val endSpacing: Int,
@Dimension protected val startSpacing: Int,
protected val recyclerView: RecyclerView,
protected val columns: Int
) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView,
state: RecyclerView.State?) {
super.getItemOffsets(outRect, view, parent, state)
val position = recyclerView.getChildAdapterPosition(view)
if (position != RecyclerView.NO_POSITION) {
val adapter = recyclerView.adapter
getItemOffsets(outRect, position, adapter?.itemCount ?: 0)
}
}
protected abstract fun getItemOffsets(outRect: Rect, position: Int, count: Int)
private class HorizontalGridSpaceItemDecoration internal constructor(
@Dimension betweenSpacing: Int,
@Dimension endSpacing: Int,
@Dimension startSpacing: Int,
recyclerView: RecyclerView,
columns: Int
) : SpaceItemDecoration(
betweenSpacing,
endSpacing,
startSpacing,
recyclerView,
columns
) {
override fun getItemOffsets(outRect: Rect, position: Int, count: Int) {
val column = position % columns
if (startSpacing > 0) {
if (position < columns) {
outRect.left = startSpacing
}
if (position + 1 == count) {
outRect.top = startSpacing
}
if (column != 0) {
outRect.bottom = betweenSpacing / 2
}
if (column + 1 != columns) {
outRect.left = betweenSpacing / 2
}
} else {
outRect.top = column * betweenSpacing / columns
outRect.bottom = betweenSpacing - (column + 1) * betweenSpacing / columns
if (position >= columns) {
outRect.left = betweenSpacing
}
}
}
}
private class HorizontalLinearSpaceItemDecoration internal constructor(
@Dimension betweenSpacing: Int,
@Dimension endSpacing: Int,
@Dimension startSpacing: Int,
recyclerView: RecyclerView,
columns: Int
) : SpaceItemDecoration(
betweenSpacing,
endSpacing,
startSpacing,
recyclerView,
columns
) {
override fun getItemOffsets(outRect: Rect, position: Int, count: Int) {
if (startSpacing > 0 || endSpacing > 0) {
if (position == 0) {
outRect.left = startSpacing
}
if (position + 1 == count) {
outRect.right = endSpacing
} else {
outRect.right = betweenSpacing
}
} else if (position + 1 != count) {
outRect.right = betweenSpacing
}
}
}
private class VerticalGridSpaceItemDecoration internal constructor(
@Dimension betweenSpacing: Int,
@Dimension endSpacing: Int,
@Dimension startSpacing: Int,
recyclerView: RecyclerView,
columns: Int
) : SpaceItemDecoration(
betweenSpacing,
endSpacing,
startSpacing,
recyclerView,
columns
) {
override fun getItemOffsets(outRect: Rect, position: Int, count: Int) {
val column = position % columns
if (startSpacing > 0 || endSpacing > 0) {
if (position < columns) {
outRect.top = startSpacing
}
if (position + 1 == count) {
outRect.bottom = endSpacing
} else {
outRect.bottom = betweenSpacing
}
if (column != 0) {
outRect.left = betweenSpacing / 2
}
if (column + 1 != columns) {
outRect.right = betweenSpacing / 2
}
} else {
outRect.left = column * betweenSpacing / columns
outRect.right = betweenSpacing - (column + 1) * betweenSpacing / columns
if (position >= columns) {
outRect.top = betweenSpacing
}
}
}
}
private class VerticalLinearSpaceItemDecoration internal constructor(
@Dimension betweenSpacing: Int,
@Dimension endSpacing: Int,
@Dimension startSpacing: Int,
recyclerView: RecyclerView,
columns: Int
) : SpaceItemDecoration(
betweenSpacing,
endSpacing,
startSpacing,
recyclerView,
columns
) {
override fun getItemOffsets(outRect: Rect, position: Int, count: Int) {
if (startSpacing > 0 || endSpacing > 0) {
if (position == 0) {
outRect.top = startSpacing
}
if (position + 1 == count) {
outRect.bottom = endSpacing
} else {
outRect.bottom = betweenSpacing
}
} else if (position + 1 != count) {
outRect.bottom = betweenSpacing
}
}
}
class Builder(private val recyclerView: RecyclerView) {
@Dimension private var betweenSpacing: Int = 0
@Dimension private var endSpacing: Int = 0
@Dimension private var startSpacing: Int = 0
fun build(): SpaceItemDecoration {
val lm = recyclerView.layoutManager
return if (lm == null) {
throw NullPointerException("recyclerView must have a LayoutManager")
} else if (lm is GridLayoutManager) {
if (lm.orientation == GridLayoutManager.HORIZONTAL) {
HorizontalGridSpaceItemDecoration(betweenSpacing, endSpacing, startSpacing,
recyclerView, lm.spanCount)
} else {
VerticalGridSpaceItemDecoration(betweenSpacing, endSpacing, startSpacing,
recyclerView, lm.spanCount)
}
} else if (lm is LinearLayoutManager) {
if (lm.orientation == LinearLayoutManager.HORIZONTAL) {
HorizontalLinearSpaceItemDecoration(betweenSpacing, endSpacing, startSpacing,
recyclerView, 1)
} else {
VerticalLinearSpaceItemDecoration(betweenSpacing, endSpacing, startSpacing,
recyclerView, 1)
}
} else {
throw IllegalArgumentException("the given LayoutManager (" +
lm.javaClass.simpleName + ") isn't a supported type")
}
}
fun setBetweenSpacing(@Dimension betweenSpacing: Int): Builder {
this.betweenSpacing = betweenSpacing
return this
}
fun setBetweenSpacingResId(@DimenRes betweenSpacingResId: Int): Builder {
setBetweenSpacing(recyclerView.resources.getDimensionPixelSize(betweenSpacingResId))
return this
}
fun setEndSpacing(@Dimension endSpacing: Int): Builder {
this.endSpacing = endSpacing
return this
}
fun setEndSpacingResId(@DimenRes endSpacingResId: Int): Builder {
setEndSpacing(recyclerView.resources.getDimensionPixelSize(endSpacingResId))
return this
}
fun setStartSpacing(@Dimension startSpacing: Int): Builder {
this.startSpacing = startSpacing
return this
}
fun setStartSpacingResId(@DimenRes startSpacingResId: Int): Builder {
setStartSpacing(recyclerView.resources.getDimensionPixelSize(startSpacingResId))
return this
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment