How to know when Shared Element Transition ends
Asked Answered
R

5

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?

Rumph answered 10/11, 2015 at 23:39 Comment(0)
O
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);
           }
      });
Oriente answered 22/11, 2015 at 20:13 Comment(11)
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 : github.com/alexjlockwood/activity-transitions/blob/master/app/…Crank
@Crank 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.Oriente
what about fragments? both solution didn't works for meMylonite
@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: github.com/Ghedeon/TransitionBugIsocyanide
Feel free to star the relevant issue: code.google.com/p/android/issues/detail?id=225415Isocyanide
@Isocyanide have you tried call "addListener()" in "onAttach()" of the fragmentB?Like here:github.com/google/iosched/blob/…Mensuration
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 @Isocyanide worksProrogue
getWindow().getSharedElementEnterTransition() always return null to be me. any thing i am missing?Cardiology
I tried the same code above and "onAnimationEnd(View view)" method is not getting called!!!. Any reasons???Pyramidon
is there a way to add animation progress update listener?Cordage
How to make this to work for below Lollipop. Because current code requires LollipopStrobe
R
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 
    }
Roundhouse answered 24/11, 2015 at 13:26 Comment(5)
Looks great, but is any suggestion on how to use it with Fragment transitions?Coven
how to use? i dont knowKcal
this solution works, until you find out that the method doesn't get called in api level less than kitkat, expected this to be called with support activity. Anyway a better option than all other methodsFred
Note that this is called before the shared element transition has finished.Gaspar
This doesn't work well for me. It's called too early. Add logs and you'll see. What works is getWindow().getSharedElementEnterTransition().addListener().Wispy
H
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) {

        }
    });
Haarlem answered 12/9, 2017 at 18:47 Comment(4)
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()Prorogue
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,Haarlem
yes, I do it like this in my fragment. if fragmentA calls FragmentB then this would be in fragmentB.Prorogue
It gets called for exit as well. why?Cordage
R
2

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

Riverhead answered 16/9, 2020 at 20:2 Comment(4)
not working for me and even get an exception: cannot be cast to TransitionSetFlagler
the import was andoirx.app, you mean I have to import from android.app ?Flagler
besides that, it seems that there is setEnterSharedElementCallback for handling onEnd but the functionality is not wellFlagler
no i meant maybe a bad import for transition setRiverhead
B
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) {
                }

            })
Bridgeman answered 10/6, 2018 at 17:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.