我在TranslateAnimation
的项目中有一个RecyclerView.Adapter
视图。动画应该在最初出现时应用于特定的列表项,但只有当您向后滚动并再次回收该项时它才会起作用。
我的猜测是它与RecyclerView的生命周期有关,但我无法弄清楚是什么导致动画无法启动。
class mAdapter(items: List<String>): RecyclerView.Adapter<mAdapter.ViewHolder>(){
private var mPosition = 0
// The animation will be applied to the first item
override fun getItemViewType(position: Int): Int {
if (position == mPosition){
return 1
} else {
return 0
}
}
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
// Animate the view inside the item
if (holder.itemViewType == 1){
holder.animateItem()
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
super.onBindViewHolder(holder, position, payloads)
// Animate the view inside the item
if (holder.itemViewType == 1){
holder.animateItem()
}
}
inner class ViewHolder(view: View): RecyclerView.ViewHolder(view){
val picture: ImageView? = view.findViewById(R.id.picture)
fun animateItem(){
val itemWidth: Float = itemView.width.toFloat()
val animator = TranslateAnimation(-itemWidth, 0f, 0f, 0f)
animator.repeatCount = 0
animator.interpolator = AccelerateInterpolator(1.0f)
animator.duration = 700
animator.fillAfter = true
background?.animation = animator
background?.startAnimation(animator)
}
}
}
如果我在animateItem
内部记录消息,它将在RecycleView加载时显示,但在我向下和向上滚动之前不会设置动画。
正如got one Related link所指出的,解决方案是编写addOnGlobalLayoutListener
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
holder.itemView.viewTreeObserver.addOnGlobalLayoutListener{
holder.animateItem()
}
}
答案 0 :(得分:0)
你是对的。 ViewHolder
仅在首次使用后的某个时间回收。不要在onViewRecycled
中进行动画制作。您可以尝试onBindViewHolder
,但我不确定您正在寻找的确切时间。
答案 1 :(得分:0)
正如评论中所讨论的,您的第一个动画实际上正在播放。
但是,第一次调用时,View在屏幕上没有完全分层。因此,override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
holder.itemView.viewTreeObserver.addOnGlobalLayoutListener{
holder.animateItem()
}
}
返回0,并且您从0到0进行动画制作。
快速解决方案是将动画的启动封装在GlobalLayoutListener(系统告诉您视图已分层)中。
这样的事情:
inline fun <T: View> T.afterMeasured(crossinline f: T.() -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (measuredWidth > 0 && measuredHeight > 0) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
f()
}
}
})
}
但是请记住,一旦你开始动画,你应该删除globalLayoutListener(否则它将永远停留在那里,并且如果/当视图发生某些事情时将继续触发)。所以更好的方法是创建一个像这样的辅助函数:
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
holder.itemView.afterMeasured{
holder.animateItem()
}
}
并在onBindViewHolder中调用它,如下所示:
history