Skip to content

Instantly share code, notes, and snippets.

@alorma
Created May 15, 2018 09:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alorma/dd9a1e5236a9febb71b635a6b4572eb0 to your computer and use it in GitHub Desktop.
Save alorma/dd9a1e5236a9febb71b635a6b4572eb0 to your computer and use it in GitHub Desktop.
import android.graphics.Canvas
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper
import android.support.v7.widget.helper.ItemTouchHelper.*
import android.view.View
import com.stronix.lio.ui.features.broadcasts.BroadcastsSwipeCallback
abstract class GenericSwipeCallback(
private var swipeLeft: SwipeAction? = null,
private var swipeRight: SwipeAction? = null
) : ItemTouchHelper.Callback() {
private var isViewBeingCleared = false
override fun getMovementFlags(recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder): Int
= makeMovementFlags(ACTION_STATE_IDLE, getAvailableDirections())
abstract fun getAvailableDirections(): Int
override fun onMove(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder?): Boolean = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val adapterPosition = viewHolder.adapterPosition
return when (direction) {
ItemTouchHelper.LEFT -> onSwipeLeft(adapterPosition)
ItemTouchHelper.START -> onSwipeLeft(adapterPosition)
ItemTouchHelper.RIGHT -> onSwipeRight(adapterPosition)
ItemTouchHelper.END -> onSwipeRight(adapterPosition)
else -> {
}
}
}
override fun clearView(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder) {
isViewBeingCleared = true
val view = viewHolder.itemView
ItemTouchHelper.Callback.getDefaultUIUtil().clearView(view)
view.alpha = BroadcastsSwipeCallback.ALPHA_COMPLETED
}
override fun onChildDraw(canvas: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
if (isViewBeingCleared) {
isViewBeingCleared = false
} else {
val itemView = viewHolder.itemView
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
if (viewHolder.adapterPosition == -1) {
return
}
processSwipeAction(canvas, itemView, dX)
} else {
ItemTouchHelper.Callback.getDefaultUIUtil()
.onDraw(canvas, recyclerView, itemView, dX, dY, actionState, isCurrentlyActive)
}
}
}
private fun processSwipeAction(canvas: Canvas, itemView: View, dX: Float) {
hideItemDependingOnDx(dX, itemView)
if (getSwipeDirection(dX) == RIGHT) {
drawBackgroundWhenSwipeRight(canvas, dX, itemView)
drawSwipeRightIcon(canvas, itemView)
} else {
drawBackgroundWhenSwipeLeft(canvas, dX, itemView)
drawSwipeLeftIcon(canvas, itemView)
}
}
private fun hideItemDependingOnDx(dX: Float, itemView: View) {
val alpha = BroadcastsSwipeCallback.ALPHA_COMPLETED - Math.abs(dX) / itemView.width.toFloat()
itemView.alpha = alpha
itemView.translationX = dX
}
private fun drawBackgroundWhenSwipeLeft(c: Canvas, dX: Float, itemView: View) {
swipeLeft?.background?.apply {
setBounds((itemView.right + dX).toInt(), itemView.top, itemView.right, itemView.bottom)
draw(c)
}
}
private fun drawBackgroundWhenSwipeRight(c: Canvas, dX: Float, itemView: View) {
swipeRight?.background?.apply {
setBounds(0, itemView.top, (itemView.left + dX).toInt(), itemView.bottom)
draw(c)
}
}
private fun getSwipeDirection(dX: Float) = if (dX > 0) RIGHT else LEFT
private fun drawSwipeLeftIcon(c: Canvas, itemView: View) {
val margin = swipeLeft?.margin ?: 0
swipeLeft?.icon?.let {
val itemMiddlePoint = getItemMiddlePoint(itemView)
val intrinsicHalfHeight = it.intrinsicHeight / 2
val intrinsicWidth = it.intrinsicWidth
val right = itemView.right - margin
val left = right - intrinsicWidth
val top = itemMiddlePoint - intrinsicHalfHeight
val bottom = itemMiddlePoint + intrinsicHalfHeight
it.setBounds(left, top, right, bottom)
it.draw(c)
}
}
private fun drawSwipeRightIcon(c: Canvas, itemView: View) {
val margin = swipeRight?.margin ?: 0
swipeRight?.icon?.let {
val itemMiddlePoint = getItemMiddlePoint(itemView)
val intrinsicHalfHeight = it.intrinsicHeight / 2
val intrinsicWidth = it.intrinsicWidth
val left = itemView.left + margin
val right = left + intrinsicWidth
val top = itemMiddlePoint - intrinsicHalfHeight
val bottom = itemMiddlePoint + intrinsicHalfHeight
it.setBounds(left, top, right, bottom)
it.draw(c)
}
}
private fun getItemMiddlePoint(itemView: View) = (itemView.bottom + itemView.top) / 2
private fun onSwipeLeft(adapterPosition: Int) {
swipeLeft?.action?.invoke(adapterPosition)
}
private fun onSwipeRight(adapterPosition: Int) {
swipeRight?.action?.invoke(adapterPosition)
}
}
swipe {
left {
color = ContextCompat.getColor(context, R.color.message_swipe_delete)
icon = drawableLeft
iconMargin = margin
action = {
// TODO
}
}
right {
color = ContextCompat.getColor(context, R.color.message_swipe_reply)
icon = drawableRight
iconMargin = margin
action = {
// TODO
}
}
}
fun RecyclerView.addSwipe(swipeController: ItemTouchHelper.Callback) {
ItemTouchHelper(swipeController).attachToRecyclerView(this)
}
import android.graphics.drawable.Drawable
class SwipeAction(val background: Drawable? = null,
val icon: Drawable? = null,
val margin: Int? = 0,
val action: (Int) -> Unit)
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper
@DslMarker
annotation class SwipeDsl
@SwipeDsl
class SwipeActionBuilder {
var color: Int? = null
var background: Drawable? = null
var icon: Drawable? = null
var iconMargin: Int = 0
lateinit var action: (Int) -> Unit
fun build(): SwipeAction = SwipeAction(background ?: color?.let { ColorDrawable(it) },
icon, iconMargin, action)
}
@SwipeDsl
class SwipeBuilder {
var swipeLeftBuilder: SwipeActionBuilder? = null
var swipeRightBuilder: SwipeActionBuilder? = null
fun build(): ItemTouchHelper.Callback? {
val swipeLeftAction = swipeLeftBuilder?.build()
val swipeRightAction = swipeRightBuilder?.build()
return object : GenericSwipeCallback(swipeLeftAction, swipeRightAction) {
override fun getAvailableDirections(): Int {
return when {
swipeLeftAction != null && swipeRightAction != null -> ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
swipeLeftAction != null -> ItemTouchHelper.LEFT
swipeRightAction != null -> ItemTouchHelper.RIGHT
else -> 0
}
}
}
}
@SwipeDsl
fun left(setup: SwipeActionBuilder.() -> Unit) {
this.swipeLeftBuilder = SwipeActionBuilder().apply(setup)
}
@SwipeDsl
fun right(setup: SwipeActionBuilder.() -> Unit) {
this.swipeRightBuilder = SwipeActionBuilder().apply(setup)
}
}
@SwipeDsl
fun recyclerViewSwipe(recyclerView: RecyclerView, setup: SwipeBuilder.() -> Unit) {
with(SwipeBuilder()) {
setup()
build()
}?.let {
ItemTouchHelper(it).attachToRecyclerView(recyclerView)
}
}
fun RecyclerView.swipe(setup: SwipeBuilder.() -> Unit) {
with(SwipeBuilder()) {
setup()
build()
}?.let {
ItemTouchHelper(it).attachToRecyclerView(this)
}
}
fun RecyclerView.leftSwipe(setup: SwipeActionBuilder.() -> Unit) {
with(SwipeBuilder()) {
swipeLeftBuilder = SwipeActionBuilder().apply(setup)
build()
}?.let {
ItemTouchHelper(it).attachToRecyclerView(this)
}
}
fun RecyclerView.rightSwipe(setup: SwipeActionBuilder.() -> Unit) {
with(SwipeBuilder()) {
swipeRightBuilder = SwipeActionBuilder().apply(setup)
build()
}?.let {
ItemTouchHelper(it).attachToRecyclerView(this)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment