Android RecyclerView网格布局动画

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

在本教程中,我们将学习如何为RecyclerView创建动画,其中的元素以Grid形式显示。

前面我们已经使用列表讨论了RecyclerView布局动画。

RecyclerView网格动画

在上一教程中,我们创建了基于列表的布局动画。
在本教程的最后,我们将它们应用于"网格布局",并看到动画仍然基于网格而不是基于行和列的列表。

为了显示基于网格的动画,我们需要使用 <gridlayoutanimation标签。
但这不适用于普通的RecyclerView。
由于默认情况下,RecyclerView对布局管理器如何放置元素一无所知,并且会采用基于列表的放置方式,因此它将崩溃。

因此,我们需要首先创建一个自定义的RecyclerView,以覆盖重要的方法。

让我们开始使用我们的应用程序。

代码

下面给出了CustomGridRecyclerView.java类的代码:

package com.theitroad.androidrecyclerviewgridlayoutanimations;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.GridLayoutAnimationController;

public class CustomGridRecyclerView extends RecyclerView {

  public CustomGridRecyclerView(Context context) {
      super(context);
  }

  public CustomGridRecyclerView(Context context, AttributeSet attrs) {
      super(context, attrs);
  }

  public CustomGridRecyclerView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
  }

  @Override
  public void setLayoutManager(LayoutManager layout) {
      if (layout instanceof GridLayoutManager) {
          super.setLayoutManager(layout);
      } else {
          throw new ClassCastException("This recyclerview should use grid layout manager as the layout manager");
      }
  }

  @Override
  protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count) {

      if (getAdapter() != null && getLayoutManager() instanceof GridLayoutManager) {

          GridLayoutAnimationController.AnimationParameters animationParams =
                  (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;

          if (animationParams == null) {
              animationParams = new GridLayoutAnimationController.AnimationParameters();
              params.layoutAnimationParameters = animationParams;
          }

          int columns = ((GridLayoutManager) getLayoutManager()).getSpanCount();

          animationParams.count = count;
          animationParams.index = index;
          animationParams.columnsCount = columns;
          animationParams.rowsCount = count/columns;

          final int invertedIndex = count - 1 - index;
          animationParams.column = columns - 1 - (invertedIndex % columns);
          animationParams.row = animationParams.rowsCount - 1 - invertedIndex/columns;

      } else {
          super.attachLayoutAnimationParameters(child, params, index, count);
      }
  }
}

在上面的代码中,我们已将RecyclerView明确设置为使用网格的行和列进行动画处理。

下面给出了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">

  <com.theitroad.androidrecyclerviewgridlayoutanimations.CustomGridRecyclerView
      android:id="@+id/recyclerView"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      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>

MainActivity.java的代码如下:

package com.theitroad.androidrecyclerviewgridlayoutanimations;

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.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.widget.GridLayout;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

  CustomGridRecyclerView recyclerView;
  RecyclerViewAdapter recyclerViewAdapter;
  FloatingActionButton fab;
  ArrayList<String> arrayList = new ArrayList<>();

  @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) {
              runAnimationAgain();
          }
      });

  }

  private void populateData() {

      for (int i = 0; i < 20; i++) {
          arrayList.add("Item " + i);
      }
  }

  private void initAdapter() {
      recyclerView.setLayoutManager(new GridLayoutManager(this, 3));

      recyclerViewAdapter = new RecyclerViewAdapter(arrayList);
      recyclerView.setAdapter(recyclerViewAdapter);
  }

  private void runAnimationAgain() {

      final LayoutAnimationController controller =
              AnimationUtils.loadLayoutAnimation(this, R.anim.gridlayout_animation_from_bottom);

      recyclerView.setLayoutAnimation(controller);
      recyclerViewAdapter.notifyDataSetChanged();
      recyclerView.scheduleLayoutAnimation();

  }
}

动画集在文件" down_to_up.xml"的" anim"文件夹中定义。

<?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>

网格布局动画在以下文件中定义:gridlayout_animation_from_bottom.xml

<?xml version="1.0" encoding="utf-8"?>
<gridLayoutAnimation xmlns:android="https://schemas.android.com/apk/res/android"
  android:animation="@anim/down_to_up"
  android:animationOrder="normal"
  android:columnDelay="15%"
  android:direction="top_to_bottom|left_to_right"
  android:rowDelay="15%"
  android:startOffset="700" 

行和列延迟属性用于在上一行获得动画之后分别定义每行和每列中动画的延迟。

下面给出了RecyclerViewAdapter.java类的代码:

package com.theitroad.androidrecyclerviewgridlayoutanimations;

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);
      }
  }
}