artem
artem

Reputation: 16777

Turn off RecyclerView child size change animation

I have a view and I want to change its size on click.

I have following layout for test:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <pro.labster.coloringbook.ui.view.ColorView
        android:id="@+id/colorView"
        android:layout_width="@dimen/colorSize"
        android:layout_height="@dimen/colorSize"
        android:layout_centerInParent="true"
        app:normalSize="@dimen/colorSize"
        app:selectedSize="@dimen/selectedColorSize" />

</RelativeLayout>

And the following code:

val colorView = findViewById<ColorView>(R.id.colorView)
colorView.setBackgroundColor(Color.RED)
colorView.setOnClickListener {
    isSelected = !isSelected
    colorView.setColorSelected(isSelected)
}

Size change code:

fun setColorSelected(isSelected: Boolean) {
        if (isColorSelected != isSelected) {
            if (isSelected) {
                setCurrentSize(selectedSize.toInt())
            } else {
                setCurrentSize(normalSize.toInt())
            }
        }

        isColorSelected = isSelected
    }

private fun setCurrentSize(size: Int) {
    if (layoutParams.height != size || layoutParams.width != size) {
        layoutParams.width = size
        layoutParams.height = size
        requestLayout()
    }
}

It works good:

https://www.youtube.com/watch?v=Ft8xcX5Qxbg

But if I add this view to RecyclerView, it lags on size change:

class ColorsAdapter(colorsHex: List<String>) : RecyclerView.Adapter<ColorsAdapter.ViewHolder>() {

    private val colors = mutableListOf<Int>()
    private var selectedPosition: Int = 0

    init {
        colorsHex.forEach {
            colors.add(Color.parseColor(it))
        }
    }

    override fun getItemCount() = colors.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val color = colors[position]

        holder.colorView.setBackgroundColor(color)
        holder.colorView.tag = position

        holder.colorView.setColorSelected(position == selectedPosition)
    }

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent?.context)

        val view = inflater.inflate(R.layout.view_item_color, parent, false)

        return ViewHolder(view)
    }


    inner class ViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
        val colorView: ColorView = itemView!!.findViewById(R.id.colorView)

        init {
            colorView.setOnClickListener {
                val oldPosition = selectedPosition

                selectedPosition = colorView.tag as Int

                if (oldPosition != selectedPosition) {
                    notifyItemChanged(oldPosition)
                    notifyItemChanged(selectedPosition)
                }
            }
        }
    }

}

view_item_color.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="@dimen/selectedColorSize"
    android:layout_height="@dimen/selectedColorSize">

    <pro.labster.coloringbook.ui.view.ColorView
        android:id="@+id/colorView"
        android:layout_width="@dimen/colorSize"
        android:layout_height="@dimen/colorSize"
        android:layout_gravity="center"
        app:normalSize="@dimen/colorSize"
        app:selectedSize="@dimen/selectedColorSize" />

</FrameLayout>

https://www.youtube.com/watch?v=m8g6zpj9aDg

As I can see, it also tries to animate size change — is it true?

And how to fix this lag?

Upvotes: 4

Views: 2255

Answers (3)

Pawel
Pawel

Reputation: 17268

You are using notifyItemChanged(position: Int), RecyclerView doesn't know what exactly changed - maybe item was replaced with another item all together, so new ViewHolder gets bound in adapters onBindViewHolder(holder: ViewHolder, position:Int) and replaces old one using default animation.

If you know explicitly what changed you can use notifyItemChanged(position: Int, payload: Any) to supply change payload for adapter, then RecyclerView will only perform partial update of a ViewHolder in adapters onBindViewHolder(holder: ViewHolder, position:Int, payloads: MutableList<Any>) and will not replace it.

For example you can change in your ViewHolder:

init {
    colorView.setOnClickListener {
    val oldPosition = selectedPosition

    selectedPosition = colorView.tag as Int

    if (oldPosition != selectedPosition) {
       notifyItemChanged(oldPosition, false)   // include payloads
       notifyItemChanged(selectedPosition, true)
       }
    }
}

Then override in your Adapter:

override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
    if(payloads.size < 1){
        //if there are no payloads perform full binding
        onBindViewHolder(holder, position)
        return
    }
    // if viewHolder can consume incremental updates iterate over payloads
    // otherwise it's enough to grab the last update
    // cast as Boolean is safe because only Booleans are passed as payloads
    holder.colorView.setColorSelected(payloads.last() as Boolean)
}

This is also a good place to start your own animations by running them on ViewHolders views (remember to override adapters onViewRecycled(holder: ViewHolder) and cancel/undo their state there)

Upvotes: 0

Ankit Jayaprakash
Ankit Jayaprakash

Reputation: 1110

You can do this by Item Animator and initialize them item animator

Upvotes: -1

azizbekian
azizbekian

Reputation: 62189

As seen in the docs of DefaultItemAnimator:

This implementation of RecyclerView.ItemAnimator provides basic animations on remove, add, and move events that happen to the items in a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.

If you want to remove those animations, then null out the default animator:

recyclerview.itemAnimator = null

Upvotes: 3

Related Questions