如何通过使用 Motion Layout 缩放来为 RecyclerView 项目设置动画片段

How to animate RecyclerView item to fragment by scaling with Motion Layout

我正在尝试重新创建与此处示例相同的动作:https://material.io/develop/android/theming/motion

具体是MaterialContainerTransform下的例子2

详细解释提出了一个从 RecyclerView 过渡到 ViewPager 的示例,但这不适用于我的情况,即 Fragment

目前我无法使这项工作正常进行,因为这是一个通用的搜索词,我希望找到的任何可能的例子都在包含 RecyclerView 和 [=15 的通用结果的海洋中=].

这是我得到的,但只有 Hold 退出时的动画有效。

对于这个项目,我使用 Java

中的导航架构组件

片段A

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setExitTransition(new Hold());
}

// this is the recycler view item click listener
private ItemClickCallback getClickCallback() {
    return (view) -> {

        FragmentNavigator.Extras extras = new FragmentNavigator.Extras
            .Builder()
            .addSharedElement(view, view.getTransitionName())
            .build();

        NavHostFragment
            .findNavController(this)
            .navigate(R.id.action_navigation, null, null, extras);

    };
}

片段 B

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setSharedElementEnterTransition(new MaterialContainerTransform());

}

就是这样。除了 Hold 动画导致的延迟外,单击已实现或未实现的项目没有区别。

这是动画库中的错误还是没有正确完成?文档没有清楚地说明如何具体针对这种情况实现这一点,我认为由于缺乏文档而没有正确完成。

似乎可用的文档缺少重要的步骤。 在我的例子中,Motion Layout 需要知道如何将点击的项目连接到要设置动画的目标视图。

我不知道在给定来自原始片段和目标片段的 1:1 视图关系时,该步骤是否通常是自动的,但在这种情况下它是一个 n:1 视图关系并且作为这样我就必须在一个包中传递 view.getTransitionName()(其他方式使用 navargs),这样它就可以告诉我们如何连接两个视图。

使用问题中的代码,需要修改如下:

片段A

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    // if hold is not used then the origin fragment might
    // disappear too soon before the target fragment is
    // fully visible
    setExitTransition(new Hold());

}

@Override
public void onViewCreated(
    @NonNull View view,
    @Nullable Bundle savedInstanceState
) {

    // this is required to animate correctly when the user returns
    // to the origin fragment, gives a chance for the layout
    // to be fully laid out before animating it
    ViewGroup viewGroup = (ViewGroup) view.getParent();
    viewGroup
        .getViewTreeObserver()
        .addOnPreDrawListener(() -> {
            startPostponedEnterTransition();
            return true;
        });

    super.onViewCreated(view, savedInstanceState);

}

// this is the recycler view item click listener
private ItemClickCallback getClickCallback() {
    return (view) -> {

        FragmentNavigator.Extras extras = new FragmentNavigator.Extras
            .Builder()
            .addSharedElement(view, view.getTransitionName())
            .build();

        Bundle bundle = new Bundle();
        bundle.putString("itemTransitionName", view.getTransitionName());

        NavHostFragment
            .findNavController(this)
            .navigate(R.id.action_navigation, bundle, null, extras);

    };
}

片段 B

String sharedViewId = "";

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    if (getArguments() != null) {
        sharedViewId = getArguments().getString("itemTransitionName");
    }

    setSharedElementEnterTransition(new MaterialContainerTransform());
    postponeEnterTransition();

}

@Override
public void onViewCreated(
    @NonNull View view,
    @Nullable Bundle savedInstanceState
) {

    // binding.getRoot() should be whichever view target you want to animate
    // in the target fragment
    ViewCompat.setTransitionName(binding.getRoot(), sharedViewId);
    super.onViewCreated(view, savedInstanceState);

}