Android_Banner.jpg
簡介
本節中我們介紹下給RecyclerView中的Item添加動畫。
添加的動畫,分為,在打開列表時有Item的展示動畫,當滑動的時候沒有動畫
和打開列表滑動時有動畫兩種
實現過程
實現一個列表
效果如下
Screenshot_2020-09-01-17-03-35-349_com.dashingqi.module.recyclerview.png
接下來我們就要操作這個列表中的Item,讓其產生動畫
布局的實現代碼
main_activity.xml 的布局文件
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
name="viewModel"
type="com.dashingqi.module.recyclerview.RvAnimationViewModel" />
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".RvAnimationActivity">
android:id="@+id/animRv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
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(
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()
val itemBinding = ItemBinding.of(BR.item, R.layout.item_anim_view)
init {
for (index in 0 until 80) {
items.add("Item${index}")
}
}
}
Adapter中的代碼
class RvAnimationAdapter(var datas: ArrayList, var recyclerView: RecyclerView) :
RecyclerView.Adapter() {
class MyViewHolder(var dataBinding: ItemAnimViewBinding) :
RecyclerView.ViewHolder(dataBinding.root) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val dataBinding = DataBindingUtil.inflate(
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的布局文件
xmlns:app="http://schemas.android.com/apk/res-auto">
name="item"
type="String" />
android:layout_width="match_parent"
android:layout_height="wrap_content">
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" />
實現進入列表時的動畫
實現效果如下
list_start.gif
該動畫是從右側平移到屏幕中,所以我們的平移動畫的X軸的起點從 100%開始,終止點為0 ,y不變
android:duration="500">
android:fromXDelta="100%p"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="0" />
android:fromAlpha="0"
android:toAlpha="100" />
接著借助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, var recyclerView: RecyclerView) :
RecyclerView.Adapter() {
/**
* 用來記錄當前是向上滑動的
*/
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(
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)
}
}
}
對應的動畫文件
android:duration="200">
android:fromYDelta="100%"
android:toYDelta="0" />
android:fromAlpha="0"
android:toAlpha="1" />
android:duration="200"
>
android:fromYDelta="-100%"
android:toYDelta="0" />
android:fromAlpha="0"
android:toAlpha="1" />