Skip to content
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

feat: correct measure with native header #2028

Merged
merged 13 commits into from
Mar 15, 2024

Conversation

WoLewicki
Copy link
Member

@WoLewicki WoLewicki commented Feb 7, 2024

Description

PR adding the getContentOriginOffset to Screen's ShadowNode in order to account for native header on both platforms. It seems like for the different screen orientations don't work correctly on Android so it needs to be investigated too. It also adds ModalScreen concept for now only to have different shadow node there. We need it for different traits since the non-modal Screen can be placed below some other views, so it should not be treated as the root of the view hierarchy by yoga.

Changes

Screenshots / GIFs

Here you can add screenshots / GIFs documenting your change.

You can add before / after section if you're changing some behavior.

Before

After

-->

Test code and steps to reproduce

It needs to be tested thoroughly with different scenarios of having headers in nested stacks etc.

Checklist

@@ -19,6 +19,7 @@ class JSI_EXPORT RNSScreenShadowNode final : public ConcreteViewShadowNode<
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;

Point getContentOriginOffset() const override;
static ShadowNodeTraits BaseTraits() {
auto traits = ConcreteViewShadowNode::BaseTraits();
traits.set(ShadowNodeTraits::Trait::RootNodeKind);
Copy link
Member

@j-piasecki j-piasecki Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll leave it here so it's not lost to time. We believe this trait is necessary for modals, but it breaks touchables (measure to be more precise) in every case where screen is not positioned at 0,0. We'd need to remove this trait here and make new shadow node specific for modals.

@tboba
Copy link
Member

tboba commented Feb 8, 2024

Hi @j-piasecki, do you think this PR is ready to check? I see that our Android builds are failing on CI at the moment and I think this is not expected 🤔

@j-piasecki
Copy link
Member

There were some things left to do, like for example compiling it on the old arch, where Wojti forgot to update the method signature 😄. The thing that needs to be for sure checked is the behavior of nested stacks with different header settings.

I think I will be able to look into it tomorrow, no promises though so if you want to do it, go ahead.

@@ -65,9 +65,9 @@ class Screen(context: ReactContext?) : FabricEnabledViewGroup(context) {
val width = r - l
val height = b - t

calculateHeaderHeight()
val headerHeight = calculateHeaderHeight()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks on the js stack, it returns the height of the header that doesn't exist

@WoLewicki WoLewicki changed the title feat: bump example to newest RN feat: correct measure with native header Feb 16, 2024
@tboba
Copy link
Member

tboba commented Feb 16, 2024

Hi @WoLewicki, could you merge the changes from main to this PR? I see that you have also bumped the version to RN 0.73.4, which is already done on main 😄

@cortinico
Copy link
Contributor

I'm also wondering what's the status here. Can we get this merged in a version of screens that comes out before RN hits 0.74 stable?

@tboba
Copy link
Member

tboba commented Feb 16, 2024

Hi @cortinico, just wanted to ask - are there any estimates when RN 0.74 will be officially published?

@cortinico
Copy link
Contributor

Hi @cortinico, just wanted to ask - are there any estimates when RN 0.74 will be officially published?

We're planning to cut the branch next week. Stable release will follow in the coming weeks so it's not immediate future but still quite high on the agenda. I just wanted to make sure this PR doesn't get forgotten

Copy link
Member

@tboba tboba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just left some comments and questions before testing the PR. Please answer them 🎉

FabricTestExample/Gemfile.lock Outdated Show resolved Hide resolved
FabricTestExample/react-native.config.js Outdated Show resolved Hide resolved
FabricTestExample/src/Test2028.tsx Outdated Show resolved Hide resolved
Comment on lines 9 to 11
+ (RNSStatusBarStyle)RNSStatusBarStyle:(id)json;
+ (UIStatusBarAnimation)UIStatusBarAnimation:(id)json;
+ (UIInterfaceOrientationMask)UIInterfaceOrientationMask:(id)json;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to have statusbar and orientation oriented methods in RNSModalScreen?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They come with RCTConvert. We could try and see if those are really needed in a follow up PR.

Comment on lines +72 to +78
const AnimatedScreen =
Platform.OS === 'android' ||
stackPresentation === 'push' ||
stackPresentation === 'containedModal' ||
stackPresentation === 'containedTransparentModal'
? AnimatedNativeScreen
: AnimatedNativeModalScreen;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add some comment here, that because how iOS modals are being mounted in view hierarchy, we need to use separate component. Also, in the future we need to check if for sure Android modals are being mounted in the same view group as usual screens (and not in the separate view, same as on iOS).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, in the future we need to check if for sure Android modals are being mounted in the same view group as usual screens (and not in the separate view, same as on iOS).

You mean in the future as when the new modals will be merged or do you mean the current situation? Currently, modals on Android are just transparent fragments with the previous ones not being detached so they are in the same view hierarchy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the modals, that will be introduced in Screens, since they may be pushed into the separate dialog hierarchy, but we'll check that, when the modal PR will be opened

src/fabric/ModalScreenNativeComponent.ts Show resolved Hide resolved
@tboba
Copy link
Member

tboba commented Feb 23, 2024

@WoLewicki also, I think I've found another issue that isn't covered with this fix. When there's a headerLargeTitle and the content is wrapped with the scrollview, touchable's target is still in the incorrect place 🤔

Screen.Recording.2024-02-23.at.17.07.10.mov

This time I see that the button is under the whole content. As I've printed calculated header's height, it gives the correct value (96, as it does not count status bar). Do you know about that case?
image

Repro
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 */

import React from 'react';
import { Button, SafeAreaView, View, ScrollView } from 'react-native';

import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { NavigationContainer } from '@react-navigation/native';

const Stack = createNativeStackNavigator();

const TestScreen = ({ navigation }): React.JSX.Element => {
  return (
    <ScrollView contentInsetAdjustmentBehavior="automatic">
      <Button
        title={
          'Click me and drag around a bit and I should log something still'
        }
        onPress={() => {
          console.log(Date.now());
        }}
      />
      <Button
        title={'Navigate to modal'}
        onPress={() => {
          navigation.navigate('Test2');
        }}
      />
    </ScrollView>
  );
};
function App(): React.JSX.Element {
  return (
    <>
      <View style={{ width: 100, height: 200, backgroundColor: 'red' }} />
      <NavigationContainer>
        <Stack.Navigator
          initialRouteName="Test"
          screenOptions={{ presentation: 'modal' }}>
          <Stack.Screen
            name="Test"
            component={TestScreen}
            options={{
              headerShown: true,
              headerLargeTitle: true,
            }}
          />
          <Stack.Screen
            name="Test2"
            component={TestScreen}
            options={{ headerShown: false }}
          />
        </Stack.Navigator>
      </NavigationContainer>
    </>
  );
}

export default App;

Comment on lines -64 to 65
#endif // RCT_NEW_ARCH_ENABLED

#else
- (instancetype)initWithBridge:(RCTBridge *)bridge
Copy link
Member

@tboba tboba Mar 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also check if new architecture is enabled in other places where we're declaring initWithBridge (e.g. RNSFullWindowOverlay, RNSSearchBar). I also see some inconsistency here - in RNSScreenStackHeaderSubview we're declaring this initWithBridge into the #pragma mark - Paper specific declaration. Maybe we should move this initializer into the pragma marks everywhere? What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's leave that on a separate PR 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we can do it in some follow-up for sure. It does not change anything on new arch since this method is just never called.

Copy link
Member

@tboba tboba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 👍

@WoLewicki WoLewicki merged commit 895606e into main Mar 15, 2024
8 checks passed
ja1ns pushed a commit to WiseOwlTech/react-native-screens that referenced this pull request Oct 9, 2024
## Description

PR adding the `getContentOriginOffset` to Screen's `ShadowNode` in order to account for native header on both platforms. It seems like for the different screen orientations don't work correctly on `Android` so it needs to be investigated too. It also adds `ModalScreen` concept for now only to have different shadow node there. We need it for different traits since the non-modal Screen can be placed below some other views, so it should not be treated as the root of the view hierarchy by yoga.

## Changes

- Added new prop to `Screen`'s state which is used in `getContentOriginOffset` method which is in turn used by `LayoutableShadowNode` when adding offsets to elements: https://github.com/facebook/react-native/blob/8da1da2e7320e23341e024a855e87c4762b220cc/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp#L54.
- Added `ModalScreen`
ja1ns pushed a commit to WiseOwlTech/react-native-screens that referenced this pull request Oct 9, 2024
…ht values (software-mansion#2075)

## Description

This PR reverts the change from another PR software-mansion#2028 that removed notifying
about header height change event. Also, here I've also included changes
that are fixing incorrect values being returned from
`calculateHeaderHeight()` function, which causes to move the target of
the touchables 🚀

## Changes

- Fixed incorrect values, returned from `calculateHeaderHeight` method
- Reverted notifying about header height change

## Test code and steps to reproduce

You can check `Test556.tsx` and `Test1072.tsx` to check if touchables
are working correctly.

## Checklist

- [ ] Ensured that CI passes
ja1ns pushed a commit to WiseOwlTech/react-native-screens that referenced this pull request Oct 9, 2024
…t set (software-mansion#2107)

## Description

All navigators except `native-stack` does not set `stackPresentation` so
it resolved in `AnimatedNativeModalScreen` making all navigators that
are nested or under some views not work with pressability. Follow-up to
software-mansion#2028

## Changes

- Added `undefined` case for setting AnimatedNativeScreen

## Test code and steps to reproduce

You can check `Test1214.tsx` or `Test2028.tsx` (after changing import to
`@react-navigation/stack`) in order to test targets of touchables.

## Checklist

- [x] Ensured that CI passes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants