How do I use a GridLayoutAnimation in a RecyclerView?

可紊 提交于 2019-11-30 00:50:41

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

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

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;

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.

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.

Simpler solution

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

But don't forget to make your RecyclerAdapter setHasStableIds(true); and implement getItemID()

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

Quoting @Musenkishi at https://gist.github.com/Musenkishi/8df1ab549857756098ba

No clue. Are you calling recyclerView.scheduleLayoutAnimation(); after setting the adapter? And have you set android:layoutAnimation="@anim/your_layout_animation" to your <GridRecyclerView> in the layout?

This solved my issue.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!