【问题标题】:Turn off RecyclerView child size change animation关闭 RecyclerView 子大小变化动画
【发布时间】:2018-01-14 14:50:13
【问题描述】:

我有一个视图,我想在点击时更改它的大小。

我有以下测试布局:

<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>

还有如下代码:

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

尺寸变更代码:

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()
    }
}

效果很好:

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

但是如果我将此视图添加到 RecyclerView,它会滞后于大小更改:

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

正如我所见,它还尝试对尺寸变化进行动画处理——是真的吗?

以及如何解决这种滞后?

【问题讨论】:

    标签: android android-recyclerview kotlin android-animation android-custom-view


    【解决方案1】:

    docs of DefaultItemAnimator中所见:

    RecyclerView.ItemAnimator 的这种实现提供了在 RecyclerView 中的项目上发生的删除、添加和移动事件的基本动画。 RecyclerView 默认使用 DefaultItemAnimator

    如果你想删除那些动画,那么就取消默认动画师:

    recyclerview.itemAnimator = null
    

    【讨论】:

      【解决方案2】:

      您正在使用notifyItemChanged(position: Int),RecyclerView 不知道到底发生了什么变化 - 可能项目被一起替换为另一个项目,所以新的 ViewHolder 被绑定到适配器 onBindViewHolder(holder: ViewHolder, position:Int) 并使用默认动画替换旧的。

      如果您明确知道发生了什么变化,您可以使用notifyItemChanged(position: Int, payload: Any) 为适配器提供更改负载,那么 RecyclerView 将仅对适配器 onBindViewHolder(holder: ViewHolder, position:Int, payloads: MutableList&lt;Any&gt;) 中的 ViewHolder 执行部分更新,并且不会替换它。

      例如,您可以更改 ViewHolder:

      init {
          colorView.setOnClickListener {
          val oldPosition = selectedPosition
      
          selectedPosition = colorView.tag as Int
      
          if (oldPosition != selectedPosition) {
             notifyItemChanged(oldPosition, false)   // include payloads
             notifyItemChanged(selectedPosition, true)
             }
          }
      }
      

      然后在您的适配器中覆盖:

      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)
      }
      

      这也是一个通过在 ViewHolders 视图上运行动画来开始您自己的动画的好地方(请记住覆盖适配器 onViewRecycled(holder: ViewHolder) 并在那里取消/撤消它们的状态)

      【讨论】:

        【解决方案3】:

        您可以通过 Item Animator 执行此操作并初始化它们 item animator

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-11
          • 2020-06-11
          • 2016-05-23
          • 2021-01-03
          • 1970-01-01
          • 2018-01-02
          相关资源
          最近更新 更多