如何在RecyclerView中使用GridLayoutAnimation? [英] How do I use a GridLayoutAnimation in a RecyclerView?

查看:75
本文介绍了如何在RecyclerView中使用GridLayoutAnimation?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用新的RecyclerView(使用GridLayoutManager)替换GridView,但是似乎它不能很好地解决gridLayoutAnimation(ClassCastException: LayoutAnimationController$AnimationParameters cannot be cast to GridLayoutAnimationController$AnimationParameters).它可以与常规布局动画配合使用,但是由于它是网格,因此在平板电脑上完成所需的时间太长.

I'm trying to replace my GridView with the new RecyclerView (using GridLayoutManager) but it seems like it doesn't cope well with gridLayoutAnimation (ClassCastException: LayoutAnimationController$AnimationParameters cannot be cast to GridLayoutAnimationController$AnimationParameters). It works with a regular layout animation, but because it's a grid, it takes too long to complete on tablets.

我要完成的工作类似于分层的时间.如果您观看示例视频,它显示了布局动画从左上角到右下角对角线.常规布局动画会逐行执行动画,因此在较大的网格(例如平板电脑)上花费太多时间才能完成.我也曾尝试探索ItemAnimator,但这只会像在"Do n't"示例中一样,在所有单元格上同时运行动画.

What I'm trying to accomplish is similar to Hierarchical Timing. If you look at the example video, it shows the layout animation go from top-left to down-right diagonally. A regular layout animation would execute the animation row after row, hence taking too much time to complete on bigger grids (e.g. tablets). I've also tried exploring ItemAnimator, but that would only run the animation on all cells simultaneously like it does in the "Don't" example.

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

Is there a way to accomplish this grid layout animation in a 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的回答,此处是仅需要您执行以下操作的解决方案使用扩展RecyclerView的自定义视图.基本上只覆盖attachLayoutAnimationParameters()方法.与此<gridLayoutAnimation>一样,它与GridView一样.

Based on Galaxas0's answer, here is a solution which only requires you to use a custom view that extends RecyclerView. Basically only overriding the attachLayoutAnimationParameters() method. With this <gridLayoutAnimation> works as it did with 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);
        }
    }
}

推荐答案

LayoutAnimationController耦合到ViewGroup中,并且ListViewGridView都扩展了下面的方法以提供孩子的animationParams.问题是GridLayoutAnimationController需要其自己的AnimationParameters,不能进行类转换.

LayoutAnimationController is coupled into ViewGroup and both ListView and GridView extend the method below to provide the child's animationParams. The issue is that GridLayoutAnimationController requires its own AnimationParameters that cannot be class-casted.

    /**
     * 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已经完成的工作:

Since this method by default adds a LayoutAnimationController.AnimationParameters instead of GridLayoutAnimationController.AnimationParameters, the fix should be to create and attach one beforehand. What we need to implement is what GridView already does:

@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之前运行.

To replicate GridView, the closest thing we can do is shoehorn the modifications into onBindViewHolder() which allows them to run before dispatchDraw, the call that triggers animations.

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

If using RecyclerView's new GridLayoutManager, try getting parameters from that. The sample above is a proof of concept to show that it works. I've hardcoded values that don't exactly work for my application as well.

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

Since this is an API that's been around since API 1 with no real documentation or samples, I would highly suggest against using it, considering there are many ways to replicate its functionality.

这篇关于如何在RecyclerView中使用GridLayoutAnimation?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆