美文网首页Android
RecyclerView基础篇-Item添加动画

RecyclerView基础篇-Item添加动画

作者: dashingqi | 来源:发表于2020-09-01 17:56 被阅读0次
Android_Banner.jpg

简介

  • 本节中我们介绍下给RecyclerView中的Item添加动画。
  • 添加的动画,分为,在打开列表时有Item的展示动画,当滑动的时候没有动画
    和打开列表滑动时有动画两种

实现过程

实现一个列表
  • 效果如下


    Screenshot_2020-09-01-17-03-35-349_com.dashingqi.module.recyclerview.png
  • 接下来我们就要操作这个列表中的Item,让其产生动画
布局的实现代码
  • main_activity.xml 的布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>

        <variable
            name="viewModel"
            type="com.dashingqi.module.recyclerview.RvAnimationViewModel" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".RvAnimationActivity">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/animRv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
  • MainActivity.kt中的代码
lass RvAnimationActivity : AppCompatActivity() {

    private val animationDownToUp by lazy {
        AnimationUtils.loadAnimation(this, R.anim.item_anim_down_to_up)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val dataBinding = DataBindingUtil.setContentView<ActivityRvAnimationBinding>(
            this,
            R.layout.activity_rv_animation
        )
        
//获取到ViewModel的实例
        val viewModel = ViewModelProvider(this)[RvAnimationViewModel::class.java]
      //绑定ViewModel
        dataBinding.viewModel = viewModel
      //设置适配器
        var adapter = RvAnimationAdapter(viewModel.items, animRv)
        animRv.adapter = adapter
        // 为Rv中的Item添加装饰器
        animRv.addItemDecoration(object : RecyclerView.ItemDecoration() {
            override fun getItemOffsets(
                outRect: Rect,
                view: View,
                parent: RecyclerView,
                state: RecyclerView.State
            ) {
                val childPosition = parent.getChildAdapterPosition(view)
                if (childPosition != 0) {
                    outRect.top = DensityUtils.dip2pxInt(parent.context, 16f)
                }
            }
        })
    }
}
  • ViewModel中的代码
class RvAnimationViewModel : ViewModel() {

    val items = ObservableArrayList<String>()
    val itemBinding = ItemBinding.of<String>(BR.item, R.layout.item_anim_view)

    init {
        for (index in 0 until 80) {
            items.add("Item${index}")
        }
    }
}
  • Adapter中的代码
class RvAnimationAdapter(var datas: ArrayList<String>, var recyclerView: RecyclerView) :
    RecyclerView.Adapter<RvAnimationAdapter.MyViewHolder>() {

    class MyViewHolder(var dataBinding: ItemAnimViewBinding) :
        RecyclerView.ViewHolder(dataBinding.root) {

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val dataBinding = DataBindingUtil.inflate<ItemAnimViewBinding>(
            LayoutInflater.from(parent.context),
            R.layout.item_anim_view,
            parent,
            false
        )

        return MyViewHolder(dataBinding)
    }

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

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val itemDataBinding = holder.dataBinding as ItemAnimViewBinding
        itemDataBinding.item = datas[position]
        itemDataBinding.executePendingBindings()
    }
}
  • item的布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="item"
            type="String" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="240dp"
            android:background="@android:color/holo_red_dark"
            android:text="@{item}"
            android:gravity="center"
            android:textColor="#ffffff"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
实现进入列表时的动画
  • 实现效果如下


    list_start.gif
  • 该动画是从右侧平移到屏幕中,所以我们的平移动画的X轴的起点从 100%开始,终止点为0 ,y不变
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">

    <translate
        android:fromXDelta="100%p"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="0" />

    <alpha
        android:fromAlpha="0"
        android:toAlpha="100" />

</set>
  • 接着借助LayoutAnimationController 给 RV的layoutAnimation设置动画数据
 val viewModel = ViewModelProvider(this)[RvAnimationViewModel::class.java]
        dataBinding.viewModel = viewModel
        var adapter = RvAnimationAdapter(viewModel.items, animRv)
        animRv.adapter = adapter


        var animation = AnimationUtils.loadAnimation(this, R.anim.item_anim_translate)
        val layoutAnimationController = LayoutAnimationController(animation)
        //设置顺序
        layoutAnimationController.order = LayoutAnimationController.ORDER_NORMAL
        animRv.layoutAnimation = layoutAnimationController
滑动的时候带有动画
  • 效果如下


    list_scroll.gif
  • 上图中的效果,是在ItemView可见的时候执行动画,我们的切入点也就是这个时机,正好Adapter中有提供一个方法onViewAttachedToWindow()

  • onViewAttachedToWindow() 是当Adapter创建好的View依附在Window的时候调用的,所以这个方法是一个时机,在这个方法中,为每一个ItemView设置动画。

  • 同时我们还需要为Rv设置滑动的监听事件,来记录滑动的方向,这样在onViewAttachedToWindow()方法中设置不同的动画

  • 所以Adapter中的代码变更如下

class RvAnimationAdapter(var datas: ArrayList<String>, var recyclerView: RecyclerView) :
    RecyclerView.Adapter<RvAnimationAdapter.MyViewHolder>() {

    /**
     * 用来记录当前是向上滑动的
     */
    var isScrollUp = false

    /**
     * 用来记录当前是向下滑动的
     */
    var isScrollDown = false

    /**
     * 动画
     */
    private val animation by lazy {
        AnimationUtils.loadAnimation(recyclerView.context, R.anim.item_anim_translate)
    }

    private val animationUpToDown by lazy {
        AnimationUtils.loadAnimation(recyclerView.context, R.anim.item_anim_up_to_down)
    }

    private val animationDownToUp by lazy {
        AnimationUtils.loadAnimation(recyclerView.context, R.anim.item_anim_down_to_up)
    }

    init {
        //为RV添加滑动事件的监听
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                isScrollUp = dy > 0
                isScrollDown = dy < 0
            }
        })


    }


    class MyViewHolder(var dataBinding: ItemAnimViewBinding) :
        RecyclerView.ViewHolder(dataBinding.root) {

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val dataBinding = DataBindingUtil.inflate<ItemAnimViewBinding>(
            LayoutInflater.from(parent.context),
            R.layout.item_anim_view,
            parent,
            false
        )

        return MyViewHolder(dataBinding)
    }

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

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val itemDataBinding = holder.dataBinding as ItemAnimViewBinding
        itemDataBinding.item = datas[position]
        itemDataBinding.executePendingBindings()
    }

    /**
     * 当创建好的View依附到Window上时回调的
     */
    override fun onViewAttachedToWindow(holder: MyViewHolder) {
        super.onViewAttachedToWindow(holder)
        for (index in 0 until recyclerView.childCount) {
            //获取到Item
            val itemView = recyclerView.getChildAt(index)
            //清除每一个Item上的动画
            itemView?.clearAnimation()
        }

        // 当向上滑动的时候
        if (isScrollUp) {
            holder.itemView.startAnimation(animationDownToUp)
        }

        //当向下滑动的时候
        if (isScrollDown) {
            holder.itemView.startAnimation(animationUpToDown)
        }
    }
}
  • 对应的动画文件
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200">


    <translate
        android:fromYDelta="100%"
        android:toYDelta="0" />

    <alpha
        android:fromAlpha="0"
        android:toAlpha="1" />

</set>


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    >

    <translate
        android:fromYDelta="-100%"
        android:toYDelta="0" />

    <alpha
        android:fromAlpha="0"
        android:toAlpha="1" />

</set>

相关文章

网友评论

    本文标题:RecyclerView基础篇-Item添加动画

    本文链接:https://www.haomeiwen.com/subject/aoivsktx.html