如何在RecyclerView中使用GridLayoutAnimation?

我试图用新的RecyclerView(使用GridLayoutManager)replace我的GridView,但它似乎不能很好地处理gridLayoutAnimation( ClassCastException: LayoutAnimationController$AnimationParameters cannot be cast to GridLayoutAnimationController$AnimationParameters )。 它使用常规的布局animation,但由于它是网格,在平板电脑上完成需要很长时间。

我试图完成的是类似于分层时序 。 如果您查看示例video,则会显示布局animation从左上angular到右下angular。 一个普通的布局animation会在一行之后执行animation行,因此在较大的网格(例如平板电脑)上花费太多的时间来完成。 我也尝试过探索ItemAnimator,但是它只会在“Do not”示例中同时在所有单元格上运行animation。

有没有一种方法可以在RecyclerView中完成这个网格布局animation?

这是gridview_layout_animation.xml:

 <!-- replace gridLayoutAnimation with layoutAnimation and --> <!-- replace column- and rowDelay with delay for RecyclerView --> <gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:columnDelay="15%" android:rowDelay="15%" android:animation="@anim/grow_in" android:animationOrder="normal" android:direction="top_to_bottom|left_to_right" android:interpolator="@android:interpolator/linear" /> 

这是animationgrow_in.xml:

 <set android:shareInterpolator="false" xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:interpolator="@android:interpolator/decelerate_quint" android:fromXScale="0.0" android:toXScale="1.0" android:fromYScale="0.0" android:toYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:fillAfter="true" android:duration="400" android:startOffset="200" /> </set> 

编辑:基于Galaxas0的答案, 这里是一个解决scheme,只需要您使用扩展RecyclerView的自定义视图。 基本上只覆盖attachLayoutAnimationParameters()方法。 使用这个<gridLayoutAnimation>与GridView一样。

 public class GridRecyclerView extends RecyclerView { public GridRecyclerView(Context context) { super(context); } public GridRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public GridRecyclerView(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("You should only use a GridLayoutManager with GridRecyclerView."); } } @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); } } } 

Solutions Collecting From Web of "如何在RecyclerView中使用GridLayoutAnimation?"

LayoutAnimationController耦合到ViewGroupListViewGridView扩展了下面的方法来提供孩子的animationParams 。 问题是GridLayoutAnimationController要求自己的AnimationParameters不能被class-cast。

  /** * Subclasses should override this method to set layout animation * parameters on the supplied child. * * @param child the child to associate with animation parameters * @param params the child's layout parameters which hold the animation * parameters * @param index the index of the child in the view group * @param count the number of children in the view group */ protected void attachLayoutAnimationParameters(View child, LayoutParams params, int index, int count) { LayoutAnimationController.AnimationParameters animationParams = params.layoutAnimationParameters; if (animationParams == null) { animationParams = new LayoutAnimationController.AnimationParameters(); params.layoutAnimationParameters = animationParams; } animationParams.count = count; animationParams.index = index; } 

由于此方法默认添加了一个LayoutAnimationController.AnimationParameters而不是GridLayoutAnimationController.AnimationParameters ,所以修复应该是预先创build并附加一个。 我们需要实现的是GridView已经做的事情:

 @Override protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count) { GridLayoutAnimationController.AnimationParameters animationParams = (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters; if (animationParams == null) { animationParams = new GridLayoutAnimationController.AnimationParameters(); params.layoutAnimationParameters = animationParams; } animationParams.count = count; animationParams.index = index; animationParams.columnsCount = mNumColumns; animationParams.rowsCount = count / mNumColumns; if (!mStackFromBottom) { animationParams.column = index % mNumColumns; animationParams.row = index / mNumColumns; } else { final int invertedIndex = count - 1 - index; animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns); animationParams.row = animationParams.rowsCount - 1 - invertedIndex / mNumColumns; } } 

为了复制GridView ,我们可以做的最接近的事情就是修改onBindViewHolder() ,它允许它们在dispatchDraw (触发animation的调用)之前运行。

 ViewGroup.LayoutParams params = holder.itemView.getLayoutParams(); GridLayoutAnimationController.AnimationParameters animationParams = new GridLayoutAnimationController.AnimationParameters(); params.layoutAnimationParameters = animationParams; animationParams.count = 9; animationParams.columnsCount = 3; animationParams.rowsCount = 3; animationParams.index = position; animationParams.column = position / animationParams.columnsCount; animationParams.row = position % animationParams.columnsCount; 

如果使用RecyclerView的新的GridLayoutManager ,请尝试从中获取参数。 上面的例子是一个概念certificate,表明它的工作原理。 我对硬编码的值并不完全适用于我的应用程序。

由于这是一个从API 1开始的API,没有真实的文档或示例,所以我强烈build议不要使用它,因为有很多方法来复制它的function。

更简单的解决scheme

 TransitionManager.beginDelayedTransition(moviesGridRecycler); gridLayoutManager.setSpanCount(gridColumns); adapter.notifyDataSetChanged(); 

但不要忘记让你的RecyclerAdapter setHasStableIds(true); 并实现getItemID()

 @Override public long getItemId(int position) { return yourItemSpecificLongID; } 

引用@Musenkishi https://gist.github.com/Musenkishi/8df1ab549857756098ba

没有线索。 你打电话给recyclerView.scheduleLayoutAnimation(); 设置适配器后? 你有没有设置android:layoutAnimation="@anim/your_layout_animation"到你的<GridRecyclerView>的布局?

这解决了我的问题。