如何通过使用 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);
}
我正在尝试重新创建与此处示例相同的动作: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);
}