不同活动之间的片段共享元素转换

5
我正在尝试在不同活动的片段之间实现共享元素转换,我已经实现了共享元素进入转换,但无法在返回时管理返回转换。
片段A托管在活动A中,在单击按钮后,将图像作为共享元素添加,并启动托管目标视图的片段B的活动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);
}
2个回答

2
简单来说,Fragment 是具有自己生命周期和逻辑的高级 ViewGroup,在 Activity 的视图树中就像任何其他 ViewGroup 一样。因此,在查看两个 Activity 之间的转换时,实际上并没有执行 Fragment 级别的共享元素转换,而是在 Activity 级别上进行转换。
需要确保在目标 Activity 中,如果目标视图(共享元素)是添加在顶部的 Fragment 的一部分,则在过渡框架开始捕获过渡结束值时,此目标视图已准备好,以便可以在视图层次结构中找到它。
FragmentManager 的 commit() 不会立即执行事务和布局更改,而是将它们安排在不久的将来进行,在您的情况下会导致上述情况不成立。延迟进入目标 Activity 的过渡,直到该 Fragment 的视图已准备好(例如,其根布局的第一个 onPreDraw() 调用),应该解决这一问题。这意味着,您必须在 Activity B 中调用 postponeEnterTransition(),而不是在 Fragment B 中,并在 activity 引用上启动 startPostponedEnterTransition() (Glide 加载侦听器的一部分),而不是在 Fragment B 自身上启动。
此外,您需要在 Activity B 上设置共享元素转换(进入和返回),因为它是实际运行它们的组件。设置了这些先决条件后,您所需的过渡应该生效。

0
这是因为imageView在片段中...它不是Activity B的元素..所以在Activity 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上也会有一个转换...


我认为这是所有从事这种活动片段框架工作的人都面临的普遍问题。 - saurabh dhillon
Backpress只是使用退出转换完成活动,但未发生任何共享元素的操作,它应该返回到其位置。 - saurabh dhillon
你检查过移除这个 finishAfterTransition(); 了吗? - Santanu Sur
我用 finish() 替换了它。 - saurabh dhillon
这些转换的名称是否相同?你测试过了吗? - Santanu Sur
显示剩余3条评论

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