【问题标题】:How do I use a GridLayoutAnimation in a RecyclerView?如何在 RecyclerView 中使用 GridLayoutAnimation?
【发布时间】:2014-10-24 00:23:34
【问题描述】:

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

我要完成的工作类似于Hierarchical Timing。如果您查看示例视频,它会显示布局动画从左上角到右下角对角线。常规布局动画会逐行执行动画,因此在更大的网格(例如平板电脑)上完成需要花费太多时间。我也尝试过探索 ItemAnimator,但这只会像“不要”示例中那样同时在所有单元格上运行动画。

有没有办法在 RecyclerView 中完成这个网格布局动画?

这是 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"
/>

这是动画grow_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 的回答,here 是一种解决方案,只需要您使用扩展 RecyclerView 的自定义视图。基本上只覆盖attachLayoutAnimationParameters() 方法。使用此&lt;gridLayoutAnimation&gt; 就像使用 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);
        }
    }
}

【问题讨论】:

    标签: android android-recyclerview layout-animation


    【解决方案1】:

    LayoutAnimationControllerViewGroup 耦合,ListViewGridView 都扩展下面的方法以提供孩子的animationParams。问题是 GridLayoutAnimationController 需要自己的 AnimationParameters 不能进行类强制转换。

        /**
         * 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,因此修复方法应该是预先创建并附加一个。我们需要实现的是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(触发动画的调用)之前运行。

    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,请尝试从中获取参数。上面的示例是一个概念证明,表明它有效。我硬编码的值也不适用于我的应用程序。

    由于这是一个自 API 1 以来就存在的 API,没有真正的文档或示例,我强烈建议不要使用它,因为有很多方法可以复制其功能。

    【讨论】:

    • 你能解释一下怎么做吗?我已经尝试使用默认的 ItemAnimator 以及下载不同 ItemAnimators 的示例,但我似乎无法找到我正在寻找的动画。
    • 您确定不使用notifyDataSetChanged(),而是使用notifyItemRangeAdded()notifyItemRangeRemoved()?这应该总是触发首次加载动画。
    • 是的,我尝试过使用notifyItemRangeAdded(),但正如我上面所描述的,它并没有给我想要的行为。 notifyItemRangeAdded() 将在第一行运行动画,从第二行开始,直到第一行中的所有单元格都开始动画。我可以从&lt;gridLayoutAnimation&gt; 获得的动画可以沿对角线穿过行,这意味着它可以同时开始为多行设置动画。本质上是让网格中的所有单元格从左上角到右下角以波浪的形式出现。
    • 嗯,这是真的。您是否尝试过用代码而不是 xml 来创建布局动画?
    • 我已经用调查结果更新了我的答案,当我想出一个可靠的解决方案时,我会再次更新它。
    【解决方案2】:

    更简单的解决方案

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

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

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

    【讨论】:

      【解决方案3】:

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

      没有线索。你是在设置适配器后调用recyclerView.scheduleLayoutAnimation(); 吗?您是否在布局中将android:layoutAnimation="@anim/your_layout_animation" 设置为&lt;GridRecyclerView&gt;

      这解决了我的问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-26
        • 2018-01-04
        • 2015-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-05
        相关资源
        最近更新 更多