20

I have a use case where I mostly start an activity with a transition, but that's not the case when opening it from the navigation drawer.

To keep the transition smooth I have a Transition.TransitionListener in which I trigger some UI updating when the transition is done.

So I have something like this:

public class SomeActivity extends Activity {

    public void onCreate(Bundle savedInstanceState){ 
        // ...
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();
            sharedElementEnterTransition.addListener(new Transition.TransitionListener() {
                // ...
                @Override
                public void onTransitionEnd(Transition transition) {
                    doSomeUiUpdating();
                }
            });
        } else { // Pre-Lollipop
            doSomeUiUpdating();
        }
    }
}

This works well when starting the Activity with the animation, but how can I know if the Activity was started without a transition so that I can call doSomeUiUpdating()?

I'm sure there must be a simple method in Activity, Window, Transition or somewhere that I have overlooked. I don't want to relay on the calling Activity to set some bundle that telling if the animation is showing or not.

Roy Solberg
  • 18,133
  • 12
  • 49
  • 76
  • i will assume its the same logic as you have (if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { doSomeUiUpdating(); .... ) before the code you have to start an activity – Tasos Feb 22 '16 at 20:46
  • and transitions were added in API 19 (KITKAT) so you need to check before that not LOLLIPOP -- https://www.youtube.com/watch?v=K3yMV5am-Xo – Tasos Feb 22 '16 at 20:49
  • The thing is that - as I try to say in the first line - the activity (even though on Lollipop+) is most often started with the transition, but not when the user starts the activity from the navigation drawer. – Roy Solberg Feb 22 '16 at 20:53
  • not sure what you mean, but you can wait a second until the nav drawer is closed and then do something if that's an issue -- http://developer.android.com/intl/ru/reference/android/support/v4/widget/DrawerLayout.DrawerListener.html#onDrawerClosed(android.view.View) – Tasos Feb 22 '16 at 20:59
  • When opening the activity from the navigation drawer I don't have the shared element (an ImageView) to animate into the next activity. (I have the shared element when starting the activity from elsewhere.) – Roy Solberg Feb 22 '16 at 21:01
  • Just a dummy thought: maybe you can rely on `getTargets()` method of `Transition` (`sharedElementEnterTransition.getTargets().isEmpty()`) if it is empty or not? It's not null anyway and numbers of TargetViews maybe the solution here.. – Konstantin Loginov Feb 22 '16 at 22:10
  • Isn't sharedElementEnterTransition null when there is no transition? – drakyoko Feb 22 '16 at 22:34
  • @drakyoko no, it's not null, though it was also my initial thought. – Konstantin Loginov Feb 23 '16 at 07:40
  • The transition itself (windowSharedElementEnterTransition) is described in the theme for the app. From what I've seen so far the objects describing the transition are always the same. I haven't found any info about the shared elements themselves. @KonstantinLoginov: The targets are always empty.. – Roy Solberg Feb 23 '16 at 08:06
  • Hi. How about putting a flag into the starting Intent ? – Lev Feb 23 '16 at 11:52
  • @Lev: Yes, that's the only solution I have so far. But as I say in question; I ideally don't want to relay on the caller of the activity to set the flags right. However, I might have to go for that way of doing it. – Roy Solberg Feb 23 '16 at 12:40
  • @RoyS I'm sorry, apparently I did not read that last sentence in your post. My apologies :) – Lev Feb 23 '16 at 13:39
  • Did you try `onTransitionStart` of `TransitionListener` to set some boolean `isAnimationStarted`. – Pr38y Sep 22 '16 at 07:28

2 Answers2

4

You can try onTransitionStart of TransitionListener to set some boolean isAnimationStarted.

public class SomeActivity extends Activity {

    private boolean isAnimationStarted = false;

    public void onCreate(Bundle savedInstanceState) { 
        // ...
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();
            sharedElementEnterTransition.addListener(new Transition.TransitionListener() {
                // ...
                @Override
                public void onTransitionEnd(Transition transition) {
                    doSomeUiUpdating();
                }

                @Override
                public void onTransitionStarted(Transition transition) {
                    isAnimationStarted = true;
                }
            });
        }
    }

    public void onStart() {
        if (!isAnimationStarted) {
            doSomeUiUpdating();
        }
    }

}
Jarett Millard
  • 5,802
  • 4
  • 41
  • 48
Pr38y
  • 1,565
  • 13
  • 21
  • Nice and simple solution. :) – Roy Solberg Feb 16 '17 at 14:00
  • But won't this create a possible problem - because the callback implies an async execution, isn't it possible that even if the animation is upcoming, onStart will be called before the onTransitionStarted is called? – NeverwinterMoon May 09 '17 at 14:14
  • 3
    In fact, I just tested it and it was exactly as I said - in my case, onStart was always called before any of the callbacks, so isAnimationStarted was always false there. So, this method certainly doesn't help to determine if the activity was started with/without transition. – NeverwinterMoon May 10 '17 at 06:05
  • Did you find the right way to do this? As the comment of @NeverwinterMoon says, this doesn't exactly solve the problem. – Eduardo Pinheiro Aug 27 '17 at 17:15
4

Since you are starting an Activity, you'll be making use of an Intent to start it. You can add extras to Intents and check for them in the onCreate() of the called Activity.

Let's assume that we have 2 Activities – ActivityA, and ActivityB.

Now, let's assume that ActivityA is the calling Activity, and that ActivityB is the called Activity.

In ActivityA, let's say you've written some code to start ActivityB with a SharedElementTransition.

@Override
public void onClick(View v) {
    Intent startActivityBIntent = new Intent(getContext(), ActivityB.class);
    startActivityBIntent.putExtra("IS_SHARED_ELEMENT_TRANSITION_ENABLED", true);
    ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), view, ViewCompat.getTransitionName(view));
    startActivity(startActivityBIntent, activityOptionsCompat);
}

Now, if you notice above, I've passed an Intent extra with the putExtra() method. I've passed a Boolean value of true because I intend to start the Activity with a SharedElementTransition.

Now in ActivityB's onCreate() method, you can just check for the boolean value passed to the Intent. If you passed false, then you can add a conditional statement and perform your UI updating there. I've given you a small snippet below to help you get started:

private static final String isSharedElementTransitionEnabled = "IS_SHARED_ELEMENT_TRANSITION_ENABLED";    

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);

    // If you are postponing your SharedElementTransition, don't forget to call postponeEnterTransition() and override onPreDraw()

    if (!getIntent().getExtras().getBoolean(isSharedElementTransitionEnabled)) {
        //Do your UI updation here
    }
}

The good thing about doing it this way is that you can then have full control over how your content transitions and your shared element transitions will play out.

gadgetroid
  • 83
  • 4