Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android reverse shared element transition on back after orientation change?

For shared element transition I am following this github project. It has 2 screens - one with recyclerview having number of cards & second the detail screen. As expected, it exhibits shared element transition of imageview & textview from recyclerview item to detail screen & reverse transition on back press.

But, if user changes orientation on detail screen, & then presses back button then the reverse transition animation doesn't work. Looking at this video's frames between 2:49 to 2:57 it seems to be possible even after orientation change. Any idea on this?

Edit:

Please check this video for better understanding.

like image 223
Ankur Avatar asked Mar 13 '15 13:03

Ankur


4 Answers

If you go into "Developer options" and enable "Don't keep activities", I think you'll find the problem will occur as well. In other words, the problem isn't that you are rotating the device... but more generally that the first activity is being destroyed while in the background.

Looking at your sample code, it looks like you're doing some weird stuff with an adapter (i.e. feeding the recycler view new grid items every 50ms from a background thread)? I can see why that might cause some issues for you... for example, what if the calling activity is destroyed and needs to be recreated immediately after the user clicks the back button and the return transition begins? If the shared element return transition begins and the desired shared element does not yet exist in the first activity (for example, because it has not yet been added by the adapter yet), the transition will not work properly.

I think this should probably be enough information to get you started solving the problem.

like image 108
Alex Lockwood Avatar answered Nov 03 '22 09:11

Alex Lockwood


At last, I could fix this by applying separate theme to detail screen overriding following attribute value, but not sure why did this parameter change the animation behavior.

<item name="android:windowIsTranslucent">true</item>
like image 32
Ankur Avatar answered Nov 03 '22 09:11

Ankur


You have to set:

requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS);
requestWindowFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);

in the calling and the called activity (MainActivity + NextActivity in this example).

I assume you open the NextActivity by calling:

ActivityOptions options = ActivityOptions.
      makeSceneTransitionAnimation(this, new Pair<View, String>(viewToAnimate, "animationName"));
Intent intent = new Intent(MainActivity.this, NextActivity.class);
startActivity(intent, options.toBundle());

In the NextActivity you have to add:

animatingView.setTransitionName("animationName");

If you do this the transition will work if you tap the back button.

BUT if you turn the device and press the back button it won't work.

To solve this problem i added this in the first activity (MainActivity in this example):

animatingView.setTransitionName("animationName");

The system now knows what to animate after a screen rotation.

like image 2
Patrick Dorn Avatar answered Nov 03 '22 09:11

Patrick Dorn


I came across this same problem and this how I fixed it.

When the RecyclerView item is clicked, I pass the current position:

@Override
public void onItemClick(View sharedView, String transitionName, int position) {
    viewPosition = position;
    Intent intent = new Intent(this, TransitionActivity.class);
    intent.putExtra("transition", transitionName);
    ActivityOptionsCompat options = ActivityOptionsCompat.
            makeSceneTransitionAnimation(this, sharedView, transitionName);
    ActivityCompat.startActivity(this, intent, options.toBundle());
}

I save it in onSaveInstanceState to persist across configuration changes:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt(VIEW_POSITION, viewPosition);
}

Then, in the onCreate method:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Workaround for orientation change issue
    if (savedInstanceState != null) {
        viewPosition = savedInstanceState.getInt(VIEW_POSITION);
    }

    setExitSharedElementCallback(new SharedElementCallback() {
        @Override
        public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
            super.onMapSharedElements(names, sharedElements);
            if (sharedElements.isEmpty()) {
                View view = recyclerView.getLayoutManager().findViewByPosition(viewPosition);
                if (view != null) {
                    sharedElements.put(names.get(0), view);
                }
            }
        }
    });
}

Cause of the problem: the sharedElements map was empty (I don't know why) after the orientation change.

like image 1
Rúben Sousa Avatar answered Nov 03 '22 11:11

Rúben Sousa