39

I am working with Shared Element Transitions between activities. The transition is working fine but I want to know when the shared element transition ends so that I can show other things.

I tried using onSharedElementEnd in SharedElementCallback in the activity I am transition to but that gets called before the transition starts.

is there another callback i can listen for?

tyczj
  • 71,600
  • 54
  • 194
  • 296

5 Answers5

43

Did you try to bind animation listener to the shared element view inside onMapSharedElements? ViewCompat.animate(view) will give you either a new or cached ViewPropertyAnimator(Compat) and then binding the animation listener should be trivial. I haven't tried it, though.

setEnterSharedElementCallback(new SharedElementCallback() {
            @Override
            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
                super.onMapSharedElements(names, sharedElements);
                View keySharedElementView = sharedElements.get("keySharedElement");
                if(keySharedElementView != null){
                    ViewCompat.animate(keySharedElementView).setListener(new ViewPropertyAnimatorListenerAdapter(){
                        @Override
                        public void onAnimationEnd(View view) {
                            super.onAnimationEnd(view);
                        }
                    });
                }
            }
        });

What about adding Transition.Listener to the shared element transition?

 Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();
 sharedElementEnterTransition.addListener(new TransitionListenerAdapter() {
         @Override
          public void onTransitionEnd(android.support.transition.Transition transition) {
                    super.onTransitionEnd(transition);
           }
      });
Nikola Despotoski
  • 49,966
  • 15
  • 119
  • 148
  • 4
    For anyone else wondering, the `TransitionListenerAdapter` is just an empty implementation of the `Transition.TransitionListener` interface. It is likely taken from a public project by @alex-lockwood : https://github.com/alexjlockwood/activity-transitions/blob/master/app/src/main/java/com/alexjlockwood/activity/transitions/TransitionListenerAdapter.java – gnuf Feb 10 '16 at 16:58
  • 1
    @gnuf Adapter of interface is only to allow you to implement only the method you need. This is general for all listener adapters in android sdk and java. This will keep your code clean and neat. – Nikola Despotoski Feb 10 '16 at 18:06
  • 3
    what about fragments? both solution didn't works for me – Hugo Gresse Apr 24 '16 at 14:42
  • 5
    @HugoGresse that's a good question. I'd like somebody to confirm this weird behavior: simple transition, fragmentA to fragmentB (v4). All I want to know is when transition is over. So I put a listener in fragmentB like: `((Transition) getSharedElementEnterTransition()).addListener()` which is never called. But! If I also add an empty listener to the same transition in fragmentA, then both listeners start working ¯\_(ツ)_/¯. Here is the simple demo: https://github.com/Ghedeon/TransitionBug – Ghedeon Oct 16 '16 at 20:25
  • Feel free to star the relevant issue: https://code.google.com/p/android/issues/detail?id=225415 – Ghedeon Oct 19 '16 at 10:51
  • 2
    @Ghedeon have you tried call "addListener()" in "onAttach()" of the fragmentB?Like here:https://github.com/google/iosched/blob/e8c61e7e23f74aa6786696dad22e5136b423a334/android/src/main/java/com/google/samples/apps/iosched/session/SessionDetailFragment.java – wangqi060934 Feb 24 '17 at 09:14
  • I can approve that calling the getSharedElementEnterTransition() in onAttach works. I can also approve that the listener's onTransitionEnd is not called in any other method and the workaround of @Ghedeon works – luckyhandler Sep 22 '17 at 09:59
  • getWindow().getSharedElementEnterTransition() always return null to be me. any thing i am missing? – Velmurugan V Jan 30 '18 at 12:32
  • I tried the same code above and "onAnimationEnd(View view)" method is not getting called!!!. Any reasons??? – Sonu Sanjeev May 03 '18 at 07:09
  • is there a way to add animation progress update listener? – Usman Rana Aug 28 '18 at 14:27
  • How to make this to work for below Lollipop. Because current code requires Lollipop – Junaid Khan Nov 16 '20 at 06:15
20

Please try onEnterAnimationComplete() callback on your activity.

I bet this is exactly what you ere looking for.

 @Override
    public void onEnterAnimationComplete() {
        super.onEnterAnimationComplete();

    //your code 
    }
MJakhongir
  • 2,101
  • 2
  • 16
  • 27
Alex Wih
  • 1,015
  • 2
  • 11
  • 24
9

Here is what I do in a fragment:

Transition sharedElementEnterTransition = getActivity().getWindow().getSharedElementEnterTransition();
    sharedElementEnterTransition.addListener(new Transition.TransitionListener() {
        @Override
        public void onTransitionStart(Transition transition) {

        }

        @Override
        public void onTransitionEnd(Transition transition) {

        }

        @Override
        public void onTransitionCancel(Transition transition) {

        }

        @Override
        public void onTransitionPause(Transition transition) {

        }

        @Override
        public void onTransitionResume(Transition transition) {

        }
    });
Kai Wang
  • 3,303
  • 1
  • 31
  • 27
  • depending on what you want this is wrong. If you are starting your fragment transaction with a SharedElementTransition then you should call getSharedElementEnterTransition() directly without getActivity().getWindow() from your fragment - in onAttach() – luckyhandler Sep 22 '17 at 10:09
  • Hi Nino, thanks for the comment. This fragment is not the starting of transaction, but an ending. Is this a good practice for ending? Thanks, – Kai Wang Sep 25 '17 at 14:40
  • yes, I do it like this in my fragment. if fragmentA calls FragmentB then this would be in fragmentB. – luckyhandler Sep 25 '17 at 14:47
  • 1
    It gets called for exit as well. why? – Usman Rana Aug 28 '18 at 14:21
1

I was struggling to do this in Kotlin using the navigation component but managed to get it working with this

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    setAndPostponeEnterAnimation()
    _binding = PokemonDetailFragmentBinding.inflate(inflater, container, false)
    setInsets()
    handleNavigationArgs()
    return binding.root
}

private fun setAndPostponeEnterAnimation() {
    postponeEnterTransition()
    sharedElementEnterTransition = TransitionInflater.from(context)
        .inflateTransition(R.transition.shared_element_transition)
    addSharedElementListener()
}

private fun addSharedElementListener() {
    (sharedElementEnterTransition as TransitionSet).addListener((object :
        TransitionListenerAdapter() {
        override fun onTransitionEnd(transition: Transition) {
            super.onTransitionEnd(transition)
            createRevealAnimation()
        }
    }))
}

so I can wait for the shared transition to finish before starting a new animation

martinseal1987
  • 1,862
  • 8
  • 44
  • 77
0

Try to add TransitionListener on Fragment A, not B. And use android.support.transition.Transition

Fragment A

            val anim = DetailsTransition()
            anim.addListener(object : android.support.transition.Transition.TransitionListener
            {
                override fun onTransitionEnd(transition: android.support.transition.Transition) {
                }

                override fun onTransitionResume(transition: android.support.transition.Transition) {
                }

                override fun onTransitionPause(transition: android.support.transition.Transition) {
                }

                override fun onTransitionCancel(transition: android.support.transition.Transition) {
                }

                override fun onTransitionStart(transition: android.support.transition.Transition) {
                }

            })
Aksenov Vladimir
  • 677
  • 1
  • 6
  • 16