在RecyclerView中单独为视图添加动画效果

3

我还没有做过详细的调查,但是我之前没有看到这样的特性或者相关主题的信息,所以我想最好向SO寻求帮助,看看是否有人之前尝试过这个想法并能提供任何建议。如果没有,我会在找到答案后在下面发布解决方案。


期望的结果

目前我有一个用内容填充的GridView。在GridView上方有一个 FloatingActionButton,当用户点击FAB时,我想显示一个新的View。每当被点击时,我都希望每个单独的GridView项目旋转并移动到屏幕边缘,导致整个GridView部分分裂,为从底部滑入的新View腾出空间。当二次View存在时,RecyclerView将变得不可滚动,并将保持这种状态,直到用户返回。此时,相反的动画会发生,将ViewHolder带回中心并关闭间隙。


请原谅我对问题的糟糕描述。:)

动画前的GridView enter image description here

动画后的GridView enter image description here

每个视图项应该独立地执行动画,并且最终动画将模拟一种爆炸式的RecyclerView效果。


可能的方法/已尝试的方法

我目前正在阅读RecyclerView的各个元素的行为。我还从这个Android Summit video中获得了一些不错的关于RecyclerView动画的信息。

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

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

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


任何建议或推荐都将不胜感激,我会在解决问题时更新上述列表。

谢谢!

1个回答

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接