在RecyclerView中单独制作动画视图

时间:2016-07-11 15:18:43

标签: android animation gridview android-recyclerview

我还没有调查过这个问题,但是我还没有看到过这样的功能,或者发现了很多关于这个主题的信息,所以我认为最好接触到SO看看是否有人曾经玩过这个想法,并可以提供任何建议。如果没有,我会在找到解决方案时发布以下解决方案。

期望的结果

目前我有一个GridView填充了内容。我在FloatingActionButton之上有一个GridView,当用户点击FAB时,我想显示一个新的View。点击后,我希望每个GridView个项都可以旋转并向屏幕边缘移动,从而导致整个GridView分离,为新View从底部滑入腾出空间。当辅助RecyclerView出现时,View将变为不可滚动,并且将保持这种状态,直到用户返回为止,这样做会导致相反的动画发生,导致ViewHolder重新进入中心并缩小差距。

请原谅我试图解决我的问题。 :)

GridView预动画 enter image description here

动画后的GridView enter image description here

每个视图项应该相互独立动画,结束动画将模拟一种爆炸式RecyclerView效果。

可能的方法/尝试到目前为止

我目前正在阅读RecyclerView各个元素的行为。我还从Android Summit video RecyclerView动画中获得了一些非常好的信息。

现在我认为有几种不同的看法:

  1. 使用两个不同的LayoutManager并尝试在它们之间制作动画。

  2. 使用ItemDecorator更改每个ViewHolder的边距和角度。

  3. 我们将非常感谢任何建议或建议,在我解决问题时,我会更新上面的列表。

    谢谢!

1 个答案:

答案 0 :(得分:2)

能够在RecyclerView中为视图设置动画效果非常简单!您只需要一个自定义RecyclerView.LayoutManager,然后您就可以访问所有可以看到动画乐趣的视图。

此处的主要方法是getChildCount()getChildAt(int index),这两种方法如下所示getVisibleViews()您可以访问RecyclerView所有的所有观看次数目前显示。然后,我使用简单的View.animate()调用将每个视图设置为所需的X位置和旋转。我确信这也适用于所有其他类型的动画!我现在正是我想要的。 :)

这是自定义LayoutManager,请记住,如果您不扩展预定义的LayoutManager,例如GridLayoutManagerLinearLayoutManager,您需要提供更多generateDefaultLayoutParams()

等方法
public class AnimatingGridLayoutManager extends GridLayoutManager {

private static final int PARTED_ANIMATION_DURATION = 200;
private static final int PARTED_ANIMATION_VARIANCE = 20;
private static final int PARTED_ANIMATION_OFFSET = 25;
private static final int PARTED_ANIMATION_ANGLE = 15;

private boolean itemsParted;

...

public void setItemsParted(boolean itemsParted, Activity context) {
    Display display = context.getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    int screenWidth = size.x;

    if (this.itemsParted != itemsParted) {
        this.itemsParted = itemsParted;
        if (itemsParted) {
            partItems(context, screenWidth);
        } else {
            closeItems(screenWidth);
        }
    }
}

private void partItems(Context context, int screenWidth) {
    List<View> visibleViews = getVisibleViews();
    for (int i = 0; i < visibleViews.size(); i++) {
        int viewWidth = visibleViews.get(i).getWidth();
        int offset = ViewUtils.getPixelsFromDp(getRandomNumberNearInput(PARTED_ANIMATION_OFFSET), context);
        int xPos = (-viewWidth) + offset;
        int rotation = getRandomNumberNearInput(-PARTED_ANIMATION_ANGLE);

        if (viewPositionIsRight(i)) {
            // invert values to send view to end of screen instead of start
            xPos = screenWidth - offset;
            rotation = -rotation;
        }

        visibleViews.get(i).animate()
            .x(xPos)
            .rotation(rotation)
            .setDuration(PARTED_ANIMATION_DURATION)
            .setInterpolator(new FastOutSlowInInterpolator());
    }
}

private void closeItems(int screenWidth) {
    List<View> visibleViews = getVisibleViews();
    for (int i = 0; i < visibleViews.size(); i++) {
        int xPos = 0;

        if (viewPositionIsRight(i)) {
            xPos = screenWidth / 2;
        }

        visibleViews.get(i).animate()
            .x(xPos)
            .rotation(0)
            .setDuration(PARTED_ANIMATION_DURATION)
            .setInterpolator(new FastOutSlowInInterpolator());
    }
}

private boolean viewPositionIsRight(int position) {
    // if isn't 2 row grid new logic is needed
    return position % 2 != 0;
}

private int getRandomNumberNearInput(int input) {
    Random random = new Random();
    int max = input + PARTED_ANIMATION_VARIANCE;
    int min = input - PARTED_ANIMATION_VARIANCE;
    return random.nextInt(max - min) + min;
}

private List<View> getVisibleViews() {
    List<View> visibleViews = new ArrayList<>();
    for (int i = 0; i < getChildCount(); i++) {
        visibleViews.add(getChildAt(i));
    }
    return visibleViews;
}
}