item_todo.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/drag_handle"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="20dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:src="@drawable/drag_handle"/>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:layout_centerVertical="true"
android:layout_toStartOf="@id/drag_handle"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textSize="18sp"/>
</RelativeLayout>
ItemTouchHelperViewHolder.kt
interface ItemTouchHelperViewHolder {
fun onItemSelected()
fun onItemClear()
}
ItemTouItemTouchHelperAdapter.kt
interface ItemTouchHelperAdapter {
fun onItemMove(fromPosition: Int, toPosition: Int): Boolean
fun onItemRemove(position: Int)
}
##
OnRecyclerAdapterEventListener.kt
interface OnRecyclerAdapterEventListener {
fun onItemClicked(position: Int)
fun onItemLongClicked(position: Int)
fun onDragStarted(viewHolder: RecyclerView.ViewHolder)
}
SimpleItemTouchHelperCallback.kt
import android.graphics.Canvas
import android.support.v7.widget.GridLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper
class SimpleItemTouchHelperCallback(val adapter: ItemTouchHelperAdapter) :
ItemTouchHelper.Callback() {
private val MAX_ALPHA = 1.0f
override fun isItemViewSwipeEnabled(): Boolean {
return false
}
override fun isLongPressDragEnabled(): Boolean {
return false
}
override fun getMovementFlags(recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder): Int {
var dragFlags: Int
var swipeFlags: Int
if (recyclerView.layoutManager is GridLayoutManager) {
dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN or
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
swipeFlags = 0
} else {
dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
swipeFlags = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
}
return makeMovementFlags(dragFlags, swipeFlags)
}
override fun onMove(recyclerView: RecyclerView,
source: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean {
if (source.itemViewType != target.itemViewType) {
return false
}
adapter.onItemMove(source.adapterPosition, target.adapterPosition)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, position: Int) {
adapter.onItemRemove(viewHolder.adapterPosition)
}
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float, dY: Float, actionState: Int,
isCurrentlyActive: Boolean) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
val alpha = MAX_ALPHA - Math.abs(dX) / viewHolder.itemView.width
viewHolder.itemView.alpha = alpha
viewHolder.itemView.translationX = dX
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?,
actionState: Int) {
if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
if (viewHolder is ItemTouchHelperViewHolder) {
viewHolder.onItemSelected()
}
}
super.onSelectedChanged(viewHolder, actionState)
}
override fun clearView(recyclerView: RecyclerView, viewHolder:
RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
viewHolder.itemView.alpha = MAX_ALPHA
if (viewHolder is ItemTouchHelperViewHolder) {
viewHolder.onItemClear()
}
}
}
TodoListAdapter.kt
import android.content.Context
import android.graphics.Paint
import android.support.v7.widget.RecyclerView
import android.view.*
import android.widget.ImageView
import android.widget.TextView
import com.ran.todolist.R
import com.ran.todolist.common.TodoInfo
import com.ran.todolist.model.ModelManager
import com.ran.todolist.model.OnTodoInfoEventListener
import com.ran.todolist.utils.Log
import com.ran.todolist.utils.recyclerview.ItemTouchHelperAdapter
import com.ran.todolist.utils.recyclerview.OnRecyclerAdapterEventListener
import kotlinx.android.synthetic.main.item_todo.view.*
import java.util.*
import kotlin.collections.ArrayList
class TodoListAdapter(private val ctx: Context, private val categoryId: Long) :
RecyclerView.Adapter<ViewHolder>(), OnTodoInfoEventListener,
ItemTouchHelperAdapter {
private var list: ArrayList<TodoInfo> = ArrayList()
private var onEventListener: OnRecyclerAdapterEventListener? = null
fun setOnRecyclerAdapterEventListener(l: OnRecyclerAdapterEventListener) {
onEventListener = l
}
init {
ModelManager.instance.addOnTodoInfoEventListener(this)
refresh()
}
private fun refresh() {
list = ModelManager.instance.getList(categoryId)
for (i in 0 until list.size) {
Log.i("snowdeer] ${list[i]}")
}
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, position: Int): ViewHolder {
val view: View = LayoutInflater.from(ctx).inflate(R.layout.item_todo, parent, false)
return ViewHolder(view)
}
fun getItem(position: Int): TodoInfo {
return list[position]
}
override fun getItemCount(): Int {
return list.size
}
override fun onModelUpdated(info: TodoInfo) {
refresh()
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
viewHolder.text.text = list[position].text
viewHolder.text.paintFlags = when (list[position].done) {
true -> Paint.STRIKE_THRU_TEXT_FLAG
else -> 0
}
val info = list[position]
viewHolder.text.setOnLongClickListener {
Log.i("onItemLongClicked: $position")
onEventListener?.onItemLongClicked(position)
true
}
viewHolder.handle.setOnTouchListener(View.OnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
onEventListener?.onDragStarted(viewHolder);
}
false;
})
}
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
swap(fromPosition, toPosition)
return true
}
override fun onItemRemove(position: Int) {
ModelManager.instance.deleteTodoInfo(list[position])
}
private fun swap(from: Int, to: Int) {
ModelManager.instance.swap(list[from], list[to])
Collections.swap(list, from, to)
notifyItemMoved(from, to)
}
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val text: TextView = view.text
val handle: ImageView = view.drag_handle
}
TodoListFragment.kt
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.ran.todolist.R
import com.ran.todolist.utils.recyclerview.OnRecyclerAdapterEventListener
import com.ran.todolist.utils.recyclerview.SimpleItemTouchHelperCallback
import kotlinx.android.synthetic.main.fragment_todolist.view.*
private const val ARG_TAB_KEY = "ARG_TAB_KEY"
class TodoListFragment : Fragment(), OnRecyclerAdapterEventListener {
private var categoryId = 0L
private lateinit var itemTouchHelper: ItemTouchHelper
private val adapter by lazy {
TodoListAdapter(activity!!.applicationContext, categoryId)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
categoryId = it.getLong(ARG_TAB_KEY)
}
}
companion object {
fun newInstance(categoryId: Long): TodoListFragment {
return TodoListFragment().apply {
arguments = Bundle().apply {
putLong(ARG_TAB_KEY, categoryId)
}
}
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_todolist, container, false)
view.recycler_view.layoutManager = LinearLayoutManager(activity)
view.recycler_view.adapter = adapter
adapter.setOnRecyclerAdapterEventListener(this)
val callback = SimpleItemTouchHelperCallback(adapter)
itemTouchHelper = ItemTouchHelper(callback)
itemTouchHelper.attachToRecyclerView(view.recycler_view)
return view
}
override fun onItemClicked(position: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onItemLongClicked(position: Int) {
val fragment = TodoDeleteFragment()
fragment.currentItemId = adapter.getItem(position)?.id
fragment.show(activity?.supportFragmentManager, "TodoInsertFragment")
}
override fun onDragStarted(viewHolder: RecyclerView.ViewHolder) {
itemTouchHelper.startDrag(viewHolder)
}
}