Activity 两个 RecyclerView 之间的过渡
Activity Transition between two RecyclerViews
我用 GridLayout
从一个 RecyclerView
动画到另一个。它像画廊一样显示图像。
父级 RecyclerView
显示文件夹的前 3 个元素,子级 RecyclerView
显示网格中的完整内容...
主适配器
@Override
public void onBindViewHolder(FolderViewHolder holder, int position) {
holder.transitionPairs.clear();
for (int i = 0; i < 3; i++) {
ImageView iv = holder.getIconView(i);
Image image = mItems.get(position).getImages().get(i);
holder.transitionPairs.add(new Pair(iv, image.getTransitionName()));
}
子适配器
@Override
public void onBindViewHolder(ImageViewHolder holder, int position) {
ViewCompat.setTransitionName(holder.icon, mItems.get(position).getTransitionName());
}
- 两个适配器都设置了相同的转换名称,它是从图像 uri 生成的,所以它肯定是唯一的
我启动子视图如下:
Intent intent = new Intent(getActivity(), ImagesActivity.class);
intent.putExtra("folderIndex", pos);
intent.putExtra("folder", item);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), vh.getTransitionPairs().toArray(new Pair[vh.getTransitionPairs().size()]));
getActivity().startActivity(intent, options.toBundle());
}
else
getActivity().startActivity(intent);
转换对保存在 ViewHolder
中,并在绑定 ViewHolder
时生成,正如您在上面的 ViewHolders
代码中看到的那样
问题
显示子视图不是动画,返回是动画...
抱歉,这是转换框架的记录限制。
https://developer.android.com/intl/es/training/transitions/overview.html#Limitations
Limitations
This section lists some known limitations of the transitions framework:
- Classes that extend AdapterView, such as ListView, manage their child views in ways that are incompatible with the transitions framework. If you try to animate a view based on AdapterView, the device display may hang.
我知道它说 ListView
但 RecyclerView 是一样的。动画框架必须在布局视图后立即捕获 transitionName
值,而 ListView
和 RecyclerView
需要额外的时间来获取适配器、创建子视图、布局这些屏幕上的子视图,然后将它们绑定到数据。转换框架无法 "see" 那些视图。
我最好的建议是让适配器中的 "fake" 项目在实际 activity 布局上充气,只是为了过渡到 运行 上,然后 onStart您将此视图设置为 GONE
.
编辑:
基于 OP (Having issues using Android 5.0 Activity transitions onto an activity with a ViewPager) 提供的 link,我已经结束了自己的开发,但非常相似的解决方案。
在我自己的项目中,我有一个 GridLayoutManager,每个屏幕大约有 7 个元素,并且动画化为一个 LinearLayoutManager,每个视图主要有 1 个(但有时您可以看到之前或之后的角)。
在 linked 响应中,解决方案是使用 Activity.postponeEnterTransition()
、Activity.startPostponedEnterTransition()
和 OnPreDrawListener
来正确交付所有过渡。
要记住的重要事实是,视图必须附加到 window 以便过渡框架捕获它。所以我使用 OnAttachStateChangeListener
来调度转换,而不是 OnPreDraw
。这应该可以实现微妙的平滑过渡。
// somewhere on the `onBind` code I put that
itemView.addOnAttachStateChangeListener(listener);
// and this is the listener
private final View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
@Override public void onViewAttachedToWindow(View v) {
activity.startPostponedEnterTransition();
v.removeOnAttachStateChangeListener(this);
}
@Override public void onViewDetachedFromWindow(View v) {
v.removeOnAttachStateChangeListener(this);
}
};
它对我来说很好用。
1 - 确保您的 RecyclerView 有适当的视图膨胀
2 - 使用 setEnterSharedElementCallback 添加 SharedElementCallback 并覆盖 "onMapSharedElements"。
3 - 将缺少的视图添加到 sharedElements 映射(直接从您的适配器或 RecyclerView 获取它们)。
setEnterSharedElementCallback(new SharedElementCallback() {
@Override
public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
sharedElements.put("bla", recyclerView.findViewWithTag("bla"));
super.onMapSharedElements(names, sharedElements);
}
});
我用 GridLayout
从一个 RecyclerView
动画到另一个。它像画廊一样显示图像。
父级 RecyclerView
显示文件夹的前 3 个元素,子级 RecyclerView
显示网格中的完整内容...
主适配器
@Override
public void onBindViewHolder(FolderViewHolder holder, int position) {
holder.transitionPairs.clear();
for (int i = 0; i < 3; i++) {
ImageView iv = holder.getIconView(i);
Image image = mItems.get(position).getImages().get(i);
holder.transitionPairs.add(new Pair(iv, image.getTransitionName()));
}
子适配器
@Override
public void onBindViewHolder(ImageViewHolder holder, int position) {
ViewCompat.setTransitionName(holder.icon, mItems.get(position).getTransitionName());
}
- 两个适配器都设置了相同的转换名称,它是从图像 uri 生成的,所以它肯定是唯一的
我启动子视图如下:
Intent intent = new Intent(getActivity(), ImagesActivity.class);
intent.putExtra("folderIndex", pos);
intent.putExtra("folder", item);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), vh.getTransitionPairs().toArray(new Pair[vh.getTransitionPairs().size()]));
getActivity().startActivity(intent, options.toBundle());
}
else
getActivity().startActivity(intent);
转换对保存在 ViewHolder
中,并在绑定 ViewHolder
时生成,正如您在上面的 ViewHolders
代码中看到的那样
问题
显示子视图不是动画,返回是动画...
抱歉,这是转换框架的记录限制。
https://developer.android.com/intl/es/training/transitions/overview.html#Limitations
Limitations
This section lists some known limitations of the transitions framework: - Classes that extend AdapterView, such as ListView, manage their child views in ways that are incompatible with the transitions framework. If you try to animate a view based on AdapterView, the device display may hang.
我知道它说 ListView
但 RecyclerView 是一样的。动画框架必须在布局视图后立即捕获 transitionName
值,而 ListView
和 RecyclerView
需要额外的时间来获取适配器、创建子视图、布局这些屏幕上的子视图,然后将它们绑定到数据。转换框架无法 "see" 那些视图。
我最好的建议是让适配器中的 "fake" 项目在实际 activity 布局上充气,只是为了过渡到 运行 上,然后 onStart您将此视图设置为 GONE
.
编辑:
基于 OP (Having issues using Android 5.0 Activity transitions onto an activity with a ViewPager) 提供的 link,我已经结束了自己的开发,但非常相似的解决方案。
在我自己的项目中,我有一个 GridLayoutManager,每个屏幕大约有 7 个元素,并且动画化为一个 LinearLayoutManager,每个视图主要有 1 个(但有时您可以看到之前或之后的角)。
在 linked 响应中,解决方案是使用 Activity.postponeEnterTransition()
、Activity.startPostponedEnterTransition()
和 OnPreDrawListener
来正确交付所有过渡。
要记住的重要事实是,视图必须附加到 window 以便过渡框架捕获它。所以我使用 OnAttachStateChangeListener
来调度转换,而不是 OnPreDraw
。这应该可以实现微妙的平滑过渡。
// somewhere on the `onBind` code I put that
itemView.addOnAttachStateChangeListener(listener);
// and this is the listener
private final View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
@Override public void onViewAttachedToWindow(View v) {
activity.startPostponedEnterTransition();
v.removeOnAttachStateChangeListener(this);
}
@Override public void onViewDetachedFromWindow(View v) {
v.removeOnAttachStateChangeListener(this);
}
};
它对我来说很好用。
1 - 确保您的 RecyclerView 有适当的视图膨胀
2 - 使用 setEnterSharedElementCallback 添加 SharedElementCallback 并覆盖 "onMapSharedElements"。
3 - 将缺少的视图添加到 sharedElements 映射(直接从您的适配器或 RecyclerView 获取它们)。
setEnterSharedElementCallback(new SharedElementCallback() {
@Override
public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
sharedElements.put("bla", recyclerView.findViewWithTag("bla"));
super.onMapSharedElements(names, sharedElements);
}
});