Android reverse shared element transition on back after orientation change?

百般思念 提交于 2019-11-30 09:03:28

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>

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.

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!