Android RecyclerView布局动画

时间:2020-02-23 14:29:12  来源:igfitidea点击:

在本教程中,我们将在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,我们需要自定义回收者视图。