不同活动的片段之间的共享元素转换
Posted
技术标签:
【中文标题】不同活动的片段之间的共享元素转换【英文标题】:Shared element transition between fragments of different activities 【发布时间】:2018-07-30 11:09:56 【问题描述】:我正在尝试在不同活动的片段之间实现共享元素转换,我已经实现了共享元素进入转换,但无法管理回压时的返回转换。
Fragment A 托管在 Activity A 中,单击按钮时,将添加一个图像作为共享元素,并在 Fragment B 托管的位置启动 Activity B,其中包含共享元素的目标视图。
活动 A:
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.content, FragmentA.newInstance())
.commit();
@Override
public void onBackPressed()
super.onBackPressed();
finishAfterTransition();
片段 A:
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
postponeEnterTransition();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
setSharedElementReturnTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
super.onViewCreated(view, savedInstanceState);
final ImageView imageView = (ImageView) view.findViewById(R.id.simple_activity_a_imageView);
Button button = (Button) view.findViewById(R.id.simple_activity_a_btn);
button.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Intent intent = new Intent(getActivity(), ActivityB.class);
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
getActivity(),
imageView,
ViewCompat.getTransitionName(imageView));
startActivity(intent, options.toBundle());
);
活动 B:
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_to_fragment);
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.content, FragmentB.newInstance())
.commit();
@Override
public void onBackPressed()
super.onBackPressed();
finishAfterTransition();
片段 B:
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
postponeEnterTransition();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
setSharedElementReturnTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
super.onViewCreated(view, savedInstanceState);
TextView detailTextView = (TextView) view.findViewById(R.id.simple_activity_b_text);
detailTextView.setText("detail");
ImageView imageView = (ImageView) view.findViewById(R.id.simple_activity_b_image);
imageView.setVisibility(View.VISIBLE);
view.findViewById(R.id.activity_simple_two).setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
imageView.setTransitionName(getString(R.string.simple_activity_transition));
Glide.with(this)
.load(GlideFragmentA.ARMADILLO_PIC_URL)
.centerCrop()
.dontAnimate()
.listener(new RequestListener<String, GlideDrawable>()
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource)
startPostponedEnterTransition();
return false;
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource)
startPostponedEnterTransition();
return false;
)
.into(imageView);
【问题讨论】:
【参考方案1】:非常简化,Fragment 基本上是具有自己生命周期和逻辑的精美 ViewGroup,它们是 Activity 视图树的一部分,就像任何其他 ViewGroup 一样。因此,在查看两个活动之间的转换时,您实际上并不是在执行片段级别的共享元素转换,而是在活动级别进行。
有必要确保在目标活动中,如果目标视图(共享元素)是添加到顶部的片段的一部分,那么当转换框架开始捕获转换的结束值时,这个目标视图就准备好了,以便可以在视图层次结构中找到它。
FragmentManager 的 commit() 不会立即执行事务和布局更改,而是在不久之后安排它们,这在您的情况下会导致上述情况并非如此。将目标活动中的输入转换推迟到片段的视图准备就绪(例如,首先调用其根布局的 onPreDraw() )应该修复该部分。这意味着,您必须在活动 B 中调用推迟EnterTransition(),而不是在 Fragment B,在活动参考上调用 startPostponedEnterTransition()(Glide 负载侦听器的一部分) ,而不是片段 B 本身。
此外,您需要在 Activity B 上设置共享元素转换(进入和返回),因为它是实际运行它们的组件。设置了这些先决条件后,您所需的转换应该会生效。
【讨论】:
【参考方案2】:这是因为 imageView 在片段中......它不是 Activity B 的元素......所以在
活动 B 你可以做这样的事情并测试它..
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_to_fragment);
FrameLayout frame = (FrameLayout) findViewById(R.id.content);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
frame
.setTransitionName(getString(R.string.simple_activity_transition));
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.content, FragmentB.newInstance())
.commit();
@Override
public void onBackPressed()
super.onBackPressed();
finishAfterTransition();
现在您可以测试检查即使onBackPressed
也会有转换..
【讨论】:
我认为这是所有从事此类活动片段框架的人的普遍问题。 backpress 只是完成退出转换的活动,但共享元素没有任何反应,它应该返回到它的位置 你检查删除这个finishAfterTransition();
是的,我将其替换为 finish()
不只是 super.onBackPressed()
你检查了吗?以上是关于不同活动的片段之间的共享元素转换的主要内容,如果未能解决你的问题,请参考以下文章