androidkotlinandroid-coordinatorlayoutcoordinator-layout

Unable to get CoordinatorLayout LayoutParams in RecyclerView


I want to implement swipe to delete using CoordinatorLayout, so I created simple xml for each item of RecyclerView

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:id="@+id/coordinatorLayout"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/simpleModelName"
        android:layout_width="wrap_content"
        android:textSize="16sp"
        android:padding="10dp"
        android:layout_height="wrap_content" />

</android.support.design.widget.CoordinatorLayout>

And simple Adapter

open class SwipeableAdapter(val list:ArrayList<SimpleModel>) : RecyclerView.Adapter<SwipeableAdapter.ViewHolder>() {
    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        var nameTextView: TextView
        var coordinatorLayout: CoordinatorLayout

        init {
            nameTextView = view.findViewById(R.id.simpleModelName)
            coordinatorLayout = view.findViewById(R.id.coordinatorLayout)
        }
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): SwipeableAdapter.ViewHolder {
        val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.item_simple_model, viewGroup, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(viewHolder: SwipeableAdapter.ViewHolder, position: Int) {
        viewHolder.nameTextView.text = list[position].name

        var swipe = SwipeDismissBehavior<View>()
        swipe.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_END_TO_START)
        swipe.setListener(object : SwipeDismissBehavior.OnDismissListener {
            override fun onDismiss(view: View?) {
            }

            override fun onDragStateChanged(state: Int) {
            }
        })

        Log.e("onBindViewHolder","layout "+viewHolder.coordinatorLayout.javaClass.toString())
        Log.e("onBindViewHolder","layout "+viewHolder.coordinatorLayout.layoutParams.javaClass.toString())
        val coordinatorLayoutParams = viewHolder.coordinatorLayout.layoutParams as CoordinatorLayout.LayoutParams
        coordinatorLayoutParams.behavior = swipe

    }

    override fun getItemCount(): Int {
        return list.size
    }
}

The problem is with this line:

    val coordinatorLayoutParams = viewHolder.coordinatorLayout.layoutParams as CoordinatorLayout.LayoutParams

I got crash with stacktrace:

java.lang.ClassCastException: android.support.v7.widget.RecyclerView$LayoutParams cannot be cast to android.support.design.widget.CoordinatorLayout$LayoutParams
 at app.deadmc.swipeablelayout.SwipeableAdapter.onBindViewHolder(SwipeableAdapter.kt:43)
 at app.deadmc.swipeablelayout.SwipeableAdapter.onBindViewHolder(SwipeableAdapter.kt:12)
 at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6508)
 at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6541)
 at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5484)
 at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5750)
 at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5589)
 at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5585)
 at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2231)
 at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1558)
 at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1518)
 at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:610)
 at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3719)
 at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3135)
 at android.view.View.measure(View.java:19861)
 at android.support.constraint.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:934)
 at android.support.constraint.ConstraintLayout.onMeasure(ConstraintLayout.java:973)

Okay, started to check whats the problem,logged it, and found, that

        Log.e("tag","layout "+viewHolder.coordinatorLayout.javaClass.toString())
        Log.e("tag","layout "+viewHolder.coordinatorLayout.layoutParams.javaClass.toString())

Shows

12-29 13:46:16.310 19129-19129/? E/tag: layout class android.support.design.widget.CoordinatorLayout
12-29 13:46:16.310 19129-19129/? E/tag: layout class android.support.v7.widget.RecyclerView$LayoutParams

The questions are:

What am I doing wrong? Why CoordinatorLayout gives me RecyclerView$LayoutParams?


Solution

  • The coordinatorLayout is a direct child of the RecyclerView and thus has LayoutParams appropriate for this relation. The children of the CoordinatorLayout will most likely have CoordinatorLayout.LayoutParams.

    But you don't need a CoordinatorLayout to implement a swipe to delete action with a RecyclerView. It's supported directly with ItemTouchHelper and the ItemTouchHelper.Callback.onSwiped() callback.