-
-
Notifications
You must be signed in to change notification settings - Fork 533
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(iOS): non-interactive screen while switching between bottom-tab and native-stack navigators #2260
Conversation
…gator and native stack
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch! I've few questions that require answering before we can proceed, and possibly few objections to proposed solution.
[...] I've investigated that even if we're calling updateLayoutMetrics on a view, it's not being updated, since the RNSScreen implementation of that method firstly checks if parentVC is not RNSNavigationContainer and if it's not nil -> Because it's always nil during the insertion (as we're calling for screen updates too late), we're never updating layout metrics.
I do not understand a couple of things here and need some explanation.
Let me present you with my thought process first:
- On Fabric, children are initialised first with props, frame, state, etc. and mounted to the parent view component before the parent is updated with its frame & prop information.
- In
- [RNSScreenView updateLayoutMetrics: newLayoutMetrics:]
, thus when receiving Yoga frame, we're setting the frame if and only if theRNSScreenView
'sRNSScreen
view controller has parent view controller and it is not a stack view controller. - Points (1) & (2) & the fact that it is responsibility of screen container to attach
RNSScreen
into view controller hierarchy imply that the initial frame for aRNSScreenView
under a screen container is always ignored, because at the time when the initial frame is set, theRNSScreenView
is not yet mounted underRNSScreenContainerView
. This is interesting fact on it's own & I think it is not intended or at least I do not know the reason to ignore initial frame in screen container. We should definitely look into this at some later point. - Just few calls later after ignoring initial frame for
RNSScreenView
because it's view controller has not yet been mounted under screen container, we finally mount theRNSScreenView
underRNSScreenContainerView
& in themountChildComponentView:index:
method we try to setRNSScreenView
's frame before we effectively mount it by calling- markUpdated
, which fails exactly due to the same reasoning as in point (3).
Do I get that correctly?
Now, provided that we do not set the screen's frame in any other place after the screen is mounted it might be likely that bugs happens cause we did not effectively set a frame for a screen. However we do it in - [RNScreenContainerView layoutSubviews]
method <- thus here comes my next question: doesn't the system trigger the layout once the child view of container is mounted? Cause if it does not trigger the layout, then we would not set the screen's frame ever 😅 How does it happen then?
Another questions relate to the #2252 issue description. How does the presence of SafeAreaProvider
or headerShown: false
on stack navigators impact the behaviour of the screen stack? Why there is no bug when SafeAreaProvider
is not present?
And at last I have a remark to the current solution, as mounting the child before it has a frame set could possibly lead to reintroducing some bugs. I can't point to what exactly could break, but we break assumption we make in - [RNSScreenContainerView attachScreen: atIndex:]
method. Thus my suggestion would be to remain with current calling order but, for example create a separate method - [RNSScreenView updateLayoutMetrics: oldLayoutMetrics: force:]
which would set the frame forcibly if force == YES
or apply - [RNSScreenView updateLayoutMetrics: oldLayoutMetrics]
otherwise. You could also try to modify condition in - [RNSScreenView updateLayoutMetrics: oldLayoutMetrics]
, so that when parent
is nil
we allow for setting the frame.
Hey hey @kkafar, about your reasoning - yep, you're absolutely right! 😄 Frankly, I don't know why having Sure, I'll think about another approach at today's morning! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've played around with this diff on different examples & haven't seen any issue it could have caused, so I think we're good to go here. Great job!
…nd native-stack navigators (software-mansion#2260) ## Description Currently, while switching between BottomTabNavigator and NativeStackNavigator, user cannot interact with screens from BottomTabNavigator. That's because while we're coming back to the previous screen, original screen frame has frame (0, 0, 0, 0). I've investigated that even if we're calling updateLayoutMetrics on a view, it's not being updated, since the RNSScreen implementation of that method firstly checks if `parentVC` is not RNSNavigationContainer and if it's not nil -> Because it's always nil during the insertion (as we're calling for screen updates too late), we're never updating layout metrics. Fixes software-mansion#2252. ## Changes - Moved calling for parent updates before updating layout metrics. ## Screenshots / GIFs ### Before https://github.com/user-attachments/assets/8da01059-e488-43e4-ab44-2286b7cd3078 ### After https://github.com/user-attachments/assets/b7336425-bb01-4c66-80e7-4e8d83ca995d ## Test code and steps to reproduce You can test `Test2252.tsx` to check these changes. ## Checklist - [X] Included code example that can be used to test this change - [x] Ensured that CI passes
Description
Currently, while switching between BottomTabNavigator and NativeStackNavigator, user cannot interact with screens from BottomTabNavigator. That's because while we're coming back to the previous screen, original screen frame has frame (0, 0, 0, 0). I've investigated that even if we're calling updateLayoutMetrics on a view, it's not being updated, since the RNSScreen implementation of that method firstly checks if
parentVC
is not RNSNavigationContainer and if it's not nil -> Because it's always nil during the insertion (as we're calling for screen updates too late), we're never updating layout metrics.Fixes #2252.
Changes
Screenshots / GIFs
Before
Screen.Recording.2024-07-22.at.17.17.57.mov
After
Screen.Recording.2024-07-22.at.17.15.58.mov
Test code and steps to reproduce
You can test
Test2252.tsx
to check these changes.Checklist