我有一个视图,我想在点击时更改其大小。
我有以下测试布局:
<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
正如我所看到的,它也试图为尺寸变化设置动画 - 这是真的吗?
如何解决这个滞后问题?
答案 0 :(得分:2)
如docs of DefaultItemAnimator
中所示:
RecyclerView.ItemAnimator 的此实现提供了有关删除,添加和移动 RecyclerView 中项目所发生事件的基本动画。 RecyclerView 默认使用 DefaultItemAnimator 。
如果要删除这些动画,请将默认动画设备清零:
recyclerview.itemAnimator = null
答案 1 :(得分:0)
您正在使用notifyItemChanged(position: Int)
,RecyclerView不知道究竟发生了什么变化 - 也许项目被另一个项目全部替换,因此新的ViewHolder被绑定在适配器onBindViewHolder(holder: ViewHolder, position:Int)
中并使用默认动画替换旧的
如果你明确知道改变了什么,你可以使用notifyItemChanged(position: Int, payload: Any)
为适配器提供更改有效负载,那么RecyclerView将只在适配器onBindViewHolder(holder: ViewHolder, position:Int, payloads: MutableList<Any>)
中执行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)
并取消/撤消它们的状态)
答案 2 :(得分:-1)
您可以通过Item Animator执行此操作并初始化它们的项目动画