This change makes navigation screen wrapper to set absolute fill style for screen items wrendered within native stack. We obvserved an issue where screens are rendered with a versy small height when the initial style is not set properly on iOS. This change makes the screen default to full screen and only then be resized down in case navigation bars are set.
This change adds new event that gets dispatched from native stack when screen transitioning is finished.
The new event is used by react-navigation to update the library internal state that the triggered action has been finished. Previously we were relying solely on onAppear and onDisappear events, however those does not get triggered when new iOS 13 modals are used or when transparent modals are displayed. This is because with transparent modals the view below is still visible. We therefore needed another way of notifying the library that screen transition have finished despite the fact that disappear event couldn't be triggered.
As a part of this change I also refactored invalid ref cycle-break code on iOS which was ought to remove reference cycle between view and view controller. This code have been moved to viewWillDisappear callback.
Also on Android part small refactoring has been done and we removed the necessity to keep mActiveScreens array which was occasionally getting out of sync with the list of active fragments.
This change removes ScreenStackHeaderTitleView component and code that used to handle title view scaling. There were multiple issues related to scaling toolbar title views and it is not a priority at the moment to us to work on addressing those. The most frequent usecase is to put a fixed-dimensions view (e.g. logo or text) which can be now handled w/o this extra code.
When you have 2 screens in a stack with the bottom one with gestureEnabled=false using the back gesture causes the screen to become unresponsive. This seems to be caused by setting interactivePopGestureRecognizer.enabled = NO as soon as the gesture starts. This causes the gesture to cancel immediately and leaves the screen in an unresponsive state.
<Stack><Screen gestureEnabled={false} /><Screen /></Stack>
To fix this instead of using interactivePopGestureRecognizer.enabled we can leverage the existing delegate that we have in RNScreenStack. In gestureRecognizerShouldBegin we can check if the top screen has gestures enabled.
To make this simpler I moved the gestureEnabled config to Screen instead of HeaderConfig. I think it also makes more sense conceptually since the gesture is tied to the screen and not the header. It also simplifies the android code a bit.
This is a breaking change.
Update
This now only moves the config to screen since a separate fix was merged for the bug.
For customizing back button image we use platform native functionality that is: `setBackIndicatorImage` on iOS and `setHomeAsUpIndicator` on Android.
The reason we don't do that just by setting left item is that we get a couple of things for free such as handling RTL properly, working accessibility features, handling prop for hiding back button and a couple more.
Unfortunately there are some downsides to that approach too. We need to install the back button as an Image component from the JS side, and the extract the image payload on the native side to set it with the navigator. This is specifically problematic in DEV mode where images are loaded asynchronously over HTTP from the packager. In order for that to work we had to employ a few hacks (more comments on that in the code).
Previously when transparent card was requested we'd default to transparentModal stack presentation mode. However if user requests contained modal mode we should be using containedTransparentModal instead. This change fixes that behavior.
Appear event is used by react-navigation to properly dispatch focus. It is important that appear is dispatched after dismissed event. The reverse order of actions would result in getting react-navigation stack in a weird state.
It is relatively streightforward to implement onAppear event on iOS where we hook into didAppear callback from UIViewController. It gets dispatched in the right moment, that is when the transition is fully over.
On Android however it is much more tricky. There is no standard way to be notified from the fragment level that fragment transition finished. One way that is frequently recommended is to override Fragment.onCreateAnimation. However, this only works when custom transitions are provided (e.g. if we set the transition to use fade animation). As we want the platform native transition to be run by default we had to look for other ways. The current approach relies on fragment container's callbacks startViewTransition and endViewTransition, with the latter being triggered once the animation is over. We also need to take into account that a good starting point for the transition is when we call commit on fragment transaction. We use these two methods to determine if the fragment is instantiated (onCreate) within a running transaction and if so we schedule event dispatch at the moment when endViewTransition is called.
Another change this commit introduces on the Android side is that we no longer rely on show/hide for replacing fragments on stack and we now use add/remove transaction methods. Due to this change we had to make our fragments reusable and make onCreateView indempotent.