RecyclerView starting point Context menu: https://stackoverflow.com/a/27752974/4656400 ItemTouchHelper: https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf
// to avoid scrolling to recyclerview inside nested scroll view use this in the view above it
android:focusableInTouchMode="true"
class VerticalSpaceItemDecoration(vSpaceDip: Int,
headerDip: Int = -1,
footerDip: Int = -1,
val isDip: Boolean = true) : RecyclerView.ItemDecoration() {
lateinit var resources: Resources
private val header = if (headerDip == -1) vSpaceDip else headerDip
private val footer = if (footerDip == -1) vSpaceDip else footerDip
private val mVerticalSpaceHeight: Int by lazy { if (isDip) dp(vSpaceDip, resources) else vSpaceDip }
private val mHeaderHeight: Int by lazy { if (isDip) dp(header, resources) else header }
private val mFooterHeight: Int by lazy { if (isDip) dp(footer, resources) else footer }
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
resources = view.context.resources
when {
parent.getChildAdapterPosition(view) == 0 -> {
// vertical spaces for the first element
outRect.top = mHeaderHeight
outRect.bottom = mVerticalSpaceHeight
// vertical spaces for the last element
}
parent.getChildAdapterPosition(view) == parent.adapter.itemCount - 1 -> outRect.bottom = mFooterHeight
else -> // vertical spaces for other elements
outRect.bottom = mVerticalSpaceHeight
}
}
}
class HorizontalSpaceItemDecoration(vSpaceDip: Int,
headerDip: Int = -1,
footerDip: Int = -1,
val isDip: Boolean = true) : RecyclerView.ItemDecoration() {
lateinit var resources: Resources
private val header = if (headerDip == -1) vSpaceDip else headerDip
private val footer = if (footerDip == -1) vSpaceDip else footerDip
private val mVerticalSpaceHeight: Int by lazy { if (isDip) dp(vSpaceDip, resources) else vSpaceDip }
private val mHeaderHeight: Int by lazy { if (isDip) dp(header, resources) else header }
private val mFooterHeight: Int by lazy { if (isDip) dp(footer, resources) else footer }
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
resources = view.context.resources
when {
parent.getChildAdapterPosition(view) == 0 -> {
// vertical spaces for the first element
outRect.left = mHeaderHeight
outRect.right = mVerticalSpaceHeight
// vertical spaces for the last element
}
parent.getChildAdapterPosition(view) == parent.adapter.itemCount - 1 -> outRect.right = mFooterHeight
else -> // vertical spaces for other elements
outRect.right = mVerticalSpaceHeight
}
}
}
// divider in Monte app for comments (line with wome left gap)
class CommentItemDecoration(private val verticalSpaceHeight: Int,
private val headerHeight: Int,
private val footerHeight: Int) : RecyclerView.ItemDecoration() {
private var mDivider: Drawable? = null
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
val resources = parent.resources
val left = resources.dp(60)
val right = parent.width - parent.paddingRight
mDivider = ContextCompat.getDrawable(parent.context, R.drawable.comment_divider)
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
var top: Int
var bottom: Int
val params = child.layoutParams as RecyclerView.LayoutParams
if (i == 0) {
top = child.top - params.topMargin
bottom = top + mDivider!!.intrinsicHeight
drawDivider(c, parent.paddingLeft, top, right, bottom)
}
top = child.bottom + params.bottomMargin
bottom = top + mDivider!!.intrinsicHeight
drawDivider(c, left, top, right, bottom)
}
}
private fun drawDivider(c: Canvas, left: Int, top: Int, right: Int, bottom: Int) {
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(c)
}
// @Override
// public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
// RecyclerView.State state) {
// Resources resources = view.getResources();
// if (parent.getChildAdapterPosition(view) == 0) { // vertical spaces for the first element
// outRect.top = dipToPixels(headerHeight, resources);
// outRect.bottom = dipToPixels(verticalSpaceHeight, resources);
// // vertical spaces for the last element
// } else if (parent.getChildAdapterPosition(view) == parent.getAdapter().getItemCount() - 1){
// outRect.bottom = dipToPixels(footerHeight, resources);
// } else { // vertical spaces for other elements
// outRect.bottom = dipToPixels(verticalSpaceHeight, resources);
// }
// }
fun Resources.dp(dp: Int) = Math.round(dp * displayMetrics.density)
}
tools:listitem="@layout/cell_feed"
tools:showIn="@layout/content_feed"
private fun RecyclerView.enableDragging() {
val callback = object: ItemTouchHelper.Callback() {
override fun getMovementFlags(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int {
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
return makeMovementFlags(dragFlags, swipeFlags)
}
override fun onMove(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
mAdapter.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
mAdapter.onItemDismiss(viewHolder.adapterPosition)
}
override fun isLongPressDragEnabled() = true
override fun isItemViewSwipeEnabled() = true
}
val touchHelper = ItemTouchHelper(callback)
touchHelper.attachToRecyclerView(this)
}
interface ItemTouchHelperAdapter {
// drag'n'drop in firebase: https://groups.google.com/forum/#!topic/firebase-talk/UUocZUZJlRU
// and https://stackoverflow.com/questions/38135102/how-to-reorder-the-data-from-firebase-real-time-database
// and fresh one: https://stackoverflow.com/questions/46138183/drag-and-drop-in-recyclerview-using-firebase
// in recyclerview with handler: https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd
fun onItemMove(fromPosition: Int, toPosition: Int): Boolean
fun onItemDismiss(position: Int)
}
// in recycler adapter which implements TouchHelperAdapter interface
override fun onItemDismiss(position: Int) {
categories.removeAt(position)
notifyItemRemoved(position)
}
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
if (fromPosition < toPosition) {
for (i in fromPosition until toPosition) {
Collections.swap(categories, i, i + 1)
}
} else {
for (i in fromPosition downTo toPosition + 1) {
Collections.swap(categories, i, i - 1)
}
}
notifyItemMoved(fromPosition, toPosition)
return true
}
public static class ViewHolder extends RecyclerView.ViewHolder implements OnCreateContextMenuListener {
TextView tvTitle;
ImageView ivImage;
public ViewHolder(View v) {
super(v);
tvTitle =(TextView)v.findViewById(R.id.item_title);
v.setOnCreateContextMenuListener(this);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
menu.setHeaderTitle("Select The Action");
menu.add(0, v.getId(), 0, "Call");//groupId, itemId, order, title
menu.add(0, v.getId(), 0, "SMS");
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//...
recyclerView.adapter = playerAdapter
recyclerView.layoutManager = LinearLayoutManager(activity)
recyclerView.setHasFixedSize(true)
recyclerView.addItemDecoration(VerticalItemDecoration(16f))
}
class PlayerAdapter(val onItemClick: (Int) -> Unit) : RealmRecyclerViewAdapter<PlayerAdapter.PlayerVH, BookFile>() {
var selectedItemPosition = 0
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): PlayerVH {
val itemView = LayoutInflater.from(parent?.context).inflate(R.layout.item_book_file, parent, false)
val holder = PlayerVH(itemView)
return holder
}
override fun onBindViewHolder(holder: PlayerVH, position: Int) {
val file = getItem(position)
holder.title.text = file.description
Log.d("PlayerFragment","bookFiles, onBindViewHolder, position:$position, description:${file.description}")
holder.itemView.isSelected = selectedItemPosition == position
holder.itemView.setOnClickListener {
val oldPosition = selectedItemPosition
selectedItemPosition = position
notifyItemChanged(oldPosition)
notifyItemChanged(selectedItemPosition)
onItemClick(position)
}
}
class PlayerVH(view: View) : RecyclerView.ViewHolder(view) {
val title = view.findViewById(R.id.title) as TextView
}
}