Android RecyclerView布局动画
在本教程中,我们将在Android应用程序中讨论和实现RecyclerView布局动画。
Android RecyclerView布局动画
有很多方法可以使RecyclerView中的行动起来。
两种常用的经过测试的方法是:
使用ItemAnimators。
–阅读本教程。在Adapter类的
onBindViewHolder
中的每一行上设置动画
还有另一种鲜为人知但更有效的使用布局动画为RecyclerView设置动画的方法。
我们可以直接在XML中将动画资源资产传递给属性" android:layoutAnimation"。
传递的动画资源必须包含<layoutAnimation>作为根标记。
layoutAnimation在除RecyclerView之外的所有其他布局上均有效。
首先,在Android Studio项目中的res |anim
文件夹中定义一些基本的动画。
down_to_up.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="https://schemas.android.com/apk/res/android" android:duration="500"> <translate android:fromYDelta="50%p" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toYDelta="0" <alpha android:fromAlpha="0" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toAlpha="1" </set>
up_to_down.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="https://schemas.android.com/apk/res/android" android:duration="500"> <translate android:fromYDelta="-25%" android:interpolator="@android:anim/decelerate_interpolator" android:toYDelta="0" <alpha android:fromAlpha="0" android:interpolator="@android:anim/decelerate_interpolator" android:toAlpha="1" <scale android:fromXScale="125%" android:fromYScale="125%" android:interpolator="@android:anim/decelerate_interpolator" android:pivotX="50%" android:pivotY="50%" android:toXScale="100%" android:toYScale="100%" </set>
left_to_right.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="https://schemas.android.com/apk/res/android" android:duration="500"> <translate android:fromXDelta="-100%p" android:interpolator="@android:anim/decelerate_interpolator" android:toXDelta="0" <alpha android:fromAlpha="0.5" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toAlpha="1" </set>
right_to_left.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="https://schemas.android.com/apk/res/android" android:duration="500"> <translate android:fromXDelta="100%p" android:interpolator="@android:anim/decelerate_interpolator" android:toXDelta="0" <alpha android:fromAlpha="0.5" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toAlpha="1" </set>
现在,我们为每个动画集创建layoutAnimation
。
layout_animation_down_to_up.xml
<?xml version="1.0" encoding="utf-8"?> <layoutAnimation xmlns:android="https://schemas.android.com/apk/res/android" android:animation="@anim/down_to_up" android:animationOrder="normal" android:delay="15%"
layout_animation_up_to_down.xml
<?xml version="1.0" encoding="utf-8"?> <layoutAnimation xmlns:android="https://schemas.android.com/apk/res/android" android:animation="@anim/up_to_down" android:animationOrder="normal" android:delay="15%"
layout_animation_left_to_right.xml
<?xml version="1.0" encoding="utf-8"?> <layoutAnimation xmlns:android="https://schemas.android.com/apk/res/android" android:animation="@anim/left_to_right" android:animationOrder="normal" android:delay="15%"
layout_animation_right_to_left.xml
<?xml version="1.0" encoding="utf-8"?> <layoutAnimation xmlns:android="https://schemas.android.com/apk/res/android" android:animation="@anim/right_to_left" android:animationOrder="normal" android:delay="15%"
以XML和编程方式设置布局动画
我们可以通过以下方式在RecyclerView上以XML设置布局动画:
<android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:layoutAnimation="@anim/layout_animation_right_to_left"
以编程方式:
int resId = R.anim.layout_animation_right_to_left; LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(context, resId); recyclerView.setLayoutAnimation(animation);
为了重新运行动画,或者如果RecyclerView的数据集已更改,则使用以下代码:
final LayoutAnimationController controller = AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_right_to_left); recyclerView.setLayoutAnimation(controller); recyclerView.getAdapter().notifyDataSetChanged(); recyclerView.scheduleLayoutAnimation();
代码
下面给出了activity_main.xml布局的代码:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" xmlns:tools="https://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutAnimation="@anim/layout_animation_up_to_down" app:layoutManager="android.support.v7.widget.LinearLayoutManager" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp" android:src="@android:drawable/ic_media_next" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent" </android.support.constraint.ConstraintLayout>
FloatingActionButton用于切换不同的布局动画。
RecyclerView的行的布局在item_row.xml中定义,如下所示:
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" app:cardElevation="8dp" app:cardUseCompatPadding="true"> <TextView android:id="@+id/tvItem" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:text="Item X" </android.support.v7.widget.CardView>
下面给出了RecyclerViewAdapter.java
类的代码。
package com.theitroad.androidrecyclerviewlayoutanimation; import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.List; public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ItemViewHolder> { List<String> itemList; public RecyclerViewAdapter(List<String> itemList) { this.itemList = itemList; } @NonNull @Override public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_row, viewGroup, false); return new ItemViewHolder(view); } @Override public void onBindViewHolder(@NonNull ItemViewHolder myViewHolder, int position) { myViewHolder.tvItem.setText(itemList.get(position)); } @Override public int getItemCount() { return itemList == null ? 0 : itemList.size(); } public class ItemViewHolder extends RecyclerView.ViewHolder { TextView tvItem; public ItemViewHolder(@NonNull View itemView) { super(itemView); tvItem = itemView.findViewById(R.id.tvItem); } } }
下面给出了MainActivity.java类的代码:
package com.theitroad.androidrecyclerviewlayoutanimation; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.animation.AnimationUtils; import android.view.animation.GridLayoutAnimationController; import android.view.animation.LayoutAnimationController; import android.widget.Spinner; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { FloatingActionButton fab; RecyclerView recyclerView; RecyclerViewAdapter recyclerViewAdapter; ArrayList<String> arrayList = new ArrayList<>(); int[] animationList = {R.anim.layout_animation_up_to_down, R.anim.layout_animation_right_to_left, R.anim.layout_animation_down_to_up, R.anim.layout_animation_left_to_right}; int i = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fab = findViewById(R.id.fab); recyclerView = findViewById(R.id.recyclerView); populateData(); initAdapter(); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (i < animationList.length - 1) { i++; } else { i = 0; } runAnimationAgain(); } }); } private void populateData() { for (int i = 0; i < 12; i++) { arrayList.add("Item " + i); } } private void initAdapter() { recyclerViewAdapter = new RecyclerViewAdapter(arrayList); recyclerView.setAdapter(recyclerViewAdapter); } private void runAnimationAgain() { final LayoutAnimationController controller = AnimationUtils.loadLayoutAnimation(this, animationList[i]); recyclerView.setLayoutAnimation(controller); recyclerViewAdapter.notifyDataSetChanged(); recyclerView.scheduleLayoutAnimation(); } }
runAnimationAgain方法用于遍历每个动画,然后在RecyclerView上再次运行它们。
上面应用程序的输出如下:
现在,如果我们将GridLayoutManager用作布局管理器,我们将获得以下输出:
recyclerView.setLayoutManager(new GridLayoutManager(this,2,GridLayoutManager.VERTICAL,false));
上面的布局动画不是网格布局动画。
一次对每一行进行动画处理。
这是不正确的。
RecyclerView LayoutAnimation仅默认用于列表。
为了执行Grid Layout Animation,我们需要自定义回收者视图。