Shared element transition : activity into fragment nested in another activity
Asked Answered
W

1

29

i am trying to add shared element transition into my app.

Scenario is that user clicks on image thumbnail which than opens another activity with full screen image view.

This works fine if shared view is hosted directly within layout of target activity. Works smoothy for enter/exit animation. But when i'am trying to achieve similar effect within fragment which is nested in target activity this approach doesn't work. Funny thing is that enter animation is not showed, but exit animation is working fine .

Another even more complicated view hierarchy is that if target view (ImageView) is hosted within view pager which is hosted in frame layout of target activity.

Does someone had same issue ?

Edit: My click listener code

public class OnClickPicture extends OnClickBase {
  private ObjectPicture object;

  public OnClickPicture(Activity_Parent activity, ObjectPicture object) {
    super(activity);
    this.object = object;
  }

  public void onClick(View v) {

    picasso.load(object.getFullUrl()).fetch();
    Intent intent = new Intent(activity, ActivityPicture.class);
    intent.putExtra("picture_object", helper.gson.toJson(object));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && v != null) {
      Pair<View, String> p1 = Pair.create(v, "image");
      ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, p1);
      activity.startActivity(intent, options.toBundle());
    } else {
      activity.startActivity(intent);
    }

  }

}
Wernsman answered 26/7, 2016 at 17:43 Comment(0)
P
40

The way that transitions work require the new Activity to be created, measured and laid out before any animations can happen. That's so that it can find the view that you want to animate and create the appropriate animation.

In your case this isn't happening because, as stated in the docs, all FragmentTransaction.commit() does is schedule work to be done. It doesn't happen immediately. Therefore when the framework creates your Activity it cant find the view that you want to animate. That's why you don't see an entry animation but you do see an exit animation. The View is there when you leave the activity.

The solution is simple enough. First of all you can try FragmentManager.executePendingTransactions(). That still might not be enough. The transitions framework has another solution:

In the onCreate of Activity postponeEnterTransition(). This tells the framework to wait until you tell it that its safe to create the animation. That does mean that you need to tell it that its safe (via calling startPostponedEnterTransition()) at some point. In your case that would probably be in the Fragments onCreateView.

Here's an example of how that might look like:

Activity B

@Override
protected void onCreate(Bundle savedInstanceState) {
    // etc
    postponeEnterTransition();
}

Fragment B

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View sharedView = root.findViewById(R.id.shared_view);
    sharedview.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            sharedview.getViewTreeObserver().removeOnPreDrawListener(this);
            getActivity().startPostponedEnterTransition();
            return true;
        }
    });
}

Thanks to Alex Lockwood for his detailed blog posts about the Transitions framework.

Petrify answered 16/8, 2016 at 12:12 Comment(3)
You can also achieve this without adding the OnPreDrawObserver. Just override onViewCreated in your fragment and call the startPostponedEnterTransition() in thereHarrumph
Perfect and clean explanation. ThanksMyriad
@Harrumph This depends on the nature of the shared view. If it is inflated statically in the xml, your suggestion should work. If it requires a long-running task to set it up, or if it is added to the root programmatically, the OnPreDetawListener is required.Lactase

© 2022 - 2024 — McMap. All rights reserved.