This update changes the logic of how we present modals. Previously presentedModals array could get out of sync with the actual app state because in case when parent VC is not mounted, presenting a modal would silently fail. In order to handle that we added additional update trigger from where the screen stack is mounted to a window. Second change that we added here addresses a problem of concurrent calls to update modals. As we cannot update presentedModals array synchrounously (all presentation callbacks are async even when no animation is involved), we need to block future updates unless the previous batch of updates is done. To do that we added a flag that prevents method re-entry. The flag is reset when all the presentation animations are over.
After fragment library upgrade we observed a regression caused by the screens that we navigate back to being invisible. This turned out to be a problem with view restore mechanism that we don't rely on. On native android the detached view state is dumped and then view's visibility is change to GONE after screen animated away. However, since we don't rely on view state restore and instead just reuse the whole view object, when navigating back we'd move to a view with visibility set to GONE. This change workarounds this problem in the method responsible for recycling views where we reset visibility flag back to VISIBLE.
Allows you to choose additional modal presentation styles for iOS. It adds the ability to force a full screen modal or choose a "form sheet" style. This only affects iOS.
The previous condition was broken as under certain circumstances we would've receive a setReactFrame with no active screen rendered to only get the screen activate in a while. This resulted in the view dimention not being properly updated. This diff changes the condition and verifies whether a screen is mounted under UINavController or not. When not, we assume it is mounted under regular screen container and allow the frame to be adjusted from react.
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 fixes two crashes related to fragment library. The first issue was a crash caused by return transaction started while the previous transaction was ongoing (e.g., quickly adding new screen on top of the stack and immediately dismissing it). The main fix was applied in the fragment library and therefore as a part of this change we update the dependency to fragment:1.2.1 which is the current latest stable version. As a result of the fragment library change we started observing other issue. The second issue was caused by the fact that under certain circumstances the view associated with a fragment couldn't been added despite it still being attached to a parent. This was resulting in a crash. This change adds a cleanup code that properly detaches the view: we do it in onCreateView but also when the fragment destroys its view (in onViewDestroy callback). The latter is necessary because when fragments are restored the order of onCreateView calls is reversed which causes inner views to attach despite their fragment managers not being initialized.
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.
The library would crash when the `mTopScreen` instance variable is null. This change checkes if it null before calling the `getScreen()` method. It also marks the method as having a nullable return value. The only place this method is used is already setup to handle `null` responses.
This fixes a problem when image attribute of image view would get reset and we wouldn't be able to access it even in release mode. This could happen when the app is backgrounded as at that point image views release their resources. Another case that was quite frequent was that the image would start loading before the image view frame was properly set. The solution is to trigger image reload in cases when image is missing and to force the image view frame to match the size of an image.
This change also fixes a problem on iOS pre 13 where we were updating back indicator inside of the method which would run during the transition. Turns out updating this property isn't supported during animation and so we moved it out such that it is updated before the transition starts.
We currently cannot take any adventage of saving and restoring fragment state because view hierarchy of the unmounted fragment is retained by RN core anyways. Skipping sabe/restore will allow us to avoid unnecessary serializiation/deserialization of the view hierarchy but will also help circumvent some bugs which comes from the side effects of restoring. One of the bugs have been reported in #162 and in that particular case restoring result in InputText change event being triggered with stale value. This was happening in the situation when we were going back to a screen with InputText component.
This change fixes the problem with missing text selection modals when text input component is rendered under screen container. The reason turned out to be a problem with Android TextView implementation which expect the component to be attached to window at the moment when layout happens (see Editor.java#prepareCursorControllers and TextView.java$makeNewLayout). Apparently, within screens container layout will happen before the component of a given screen are attached (because attaching is managed by the fragment manager which delays the moment at which the screen is attached). As a result the textView component does not get a chance to fetch proper window layout params such that it can tell whether it should support selection mode or not. We workaround this issue by providing window layout params directly from Screen class which is used instead of the DecorWindow in case TextView is not yet attached (it searches for the top-most parent when not attached).
This change fixes a problem with native stack on Android where we'd display a sw back button on screens that are nested stack navigatodespite the fact those screens were the initial screens in the whole container stack. In #306 we introuced a change that would allow for displaying sw back in nested stacks, however that change did not handle the case where screen is a root screen of a container that is nested and placed as an initial screen in another container.
This change allows for root screens of nested stack navigators on Android to display back button in the navigation bar. Navigating back is still possible using hw back because of the way hw back is handled by nested fragment containers. However, despite hw back functioning properly, before this change we would not allow for the soft back button to be rendered in the header. This change adds this possibility to keep software back consistent with the hw back button functionality. This behavior can still be disabled/adjusted using hideBackButton property of the header config component.
This change fixes the problem when navigation bar would not get properly updated for modal transitions. The problem was due to the fact that for modal transitions the animateAlongsideTransition block was not getting trriggered. This was noticeable on iOS versions before 13, as starting with iOS 13 we can use NavigationItem to specify most of the nav bar customization. On older versions however it is required that for a lot of navbar settings we need to update them durion animation. This wasn't the case for navigators presented modally. In case we show a modal we can update nav bar without animation because it actually renders a completely new navigation bar which isn't shared.
On top of that this PR fixes the problem with bridge not being set for header subviews.
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.
This change fixes a bug when header property updates happens during or at the same time of stack transition, e.g., when we both pop a screen and change parent VC header properties. When this happens we trigger header update code, but because we used to compare current VC to visibleViewController, which at that moment points to controller that we are transitioning away from, the update would've been prevented. With this change instead of using visibleViewController to compare with updated VC, we check if there is transition happening (using transitransitionCoordinator property), and in such case we use topController which points to the controller we are transitioning to.
We believe that it might be better to manage the logic of blocking interactions from JS with setNativeProps and pointerEvents.
The current logic leads to some issues we're facing within React Navigation. There might be a state when more that one screen can be active. E.g. in modals we want to have two screens visible on the stack and have enabled interaction on the bottom one.
New code should not give any issues, because even though we need to handle activation of each screen from JS and this will just introduce an additional native call for enabling / disabling pointer events.
On iOS, we're not using React Native Screens in React Navigation for now and we'd like to focus on it later because right now we're not observing that crucial performance issues.
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.
This change removes the behavior that's been added for an unclear reason. We may consider reverting this one, however I was unable to reproduce a problem when setting header title view layout measurements was necessary. To the contrary it was causing issues in the case when the title header view updates. In such a case we would never update width/height so the updated view might be cropped. In addition we are changing the way we schedule native layout updates. Previously we'd use handler.post but it was causing one frame delay so this change migrates us to use choreographer.
This change fixes the issue with auto focusing text input fields inside native stack. Due to the fact we perform hide and show transactions in order to control back stack the hiding part would propagate visibility change event down the view hierarchy. As a result views would receive that visibility event and blur themselves resulting in textinput not getting the focus when the fragment mounts. It turns out however that for the back stack to function properly we don't need to run hide and show operation within the transaction because show is idempotent. So we change our back stack handling transaction to only call show.
This change fixes crash caused when nested stack is detached due to the parent stack being closed. As a result we may end up in a situation when fragment manager is not yet set despite onDetach callback being call. When fragment manager is not set we can also ignore the operations we should've performed in on detach. This change adds a null check before we call into fragment manager in on detach callback.
This change fixes the issue when left item added to native stack header on Android would by default be shifted from the screen edge by some amount. This turned out to be the default config of the native toolbar which applies some padding on the left side. WIn this change we reset that padding to always be 0 to let the position be specified from react. Note that the setting we reset does not influence the position of the native back navigation button as Android does not apply the padding in case navigation back icon is rendered.
Code to reproduce and test: https://snack.expo.io/@angelikaserwa/humiliated-bagel.
Switch to the Settings tab, then go back to the Home tab and press the details button. Nothing happens. It was because after re-attaching we were using a destroyed FragmentManager that was cached inside the ScreenContainer class.
Then, when we go back from Details to Home screen, using a hardware back button, an exception occured: `The specified child already has a parent. You must call removeView() on the child's parent first`.
I fixed this by calling `removeAllViews()` when detaching container from window and forcing an update on re-attach.