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

[iOS] Native Stack layout shift, initial render doesn't take header into account #1779

Open
dylancom opened this issue Jun 6, 2023 · 1 comment · May be fixed by #1998
Open

[iOS] Native Stack layout shift, initial render doesn't take header into account #1779

dylancom opened this issue Jun 6, 2023 · 1 comment · May be fixed by #1998
Assignees
Labels
Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snack or repo is provided

Comments

@dylancom
Copy link
Contributor

dylancom commented Jun 6, 2023

Description

On initial render the View within a Native Stack has an incorrect height. Upon a second render the height is corrected by taking the header into account. This causes a layout jump/shift which becomes noticable if you are vertically centering your content. Sometimes rendering happens so fast that you don't see it but in other cases it's noticable.

Caused by vc.edgesForExtendedLayout = UIRectEdgeNone; being applied after the first render.
(introduced by: https://github.com/software-mansion/react-native-screens/pull/222/files)
On for e.g. an iPhone 14 Pro the initial height is 773, which becomes 675.3333129882812 after taking into account "UIRectEdgeNone".

Expected behavior: no layout shift. The View should directly get a correct height or only be shown after the corrected height was calculated.

First render (vertically centered incorrectly) Second render
Scherm­afbeelding 2023-06-06 om 20 03 06 Scherm­afbeelding 2023-06-06 om 20 03 21

Steps to reproduce

import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen({ navigation }) {
  const [initialHeight, setInitialHeight] = React.useState(0);
  const [correctedHeight, setCorrectedHeight] = React.useState(0);

  return (
    <View
     onLayout={event => {
      const {x, y, width, height} = event.nativeEvent.layout;
      if (!initialHeight) {
        setInitialHeight(height)
      } else {
        setCorrectedHeight(height)
      }
     }}
     style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text style={{ fontSize: 20, lineHeight: 20 * 1.6, textAlign: 'center' }}>
        Initial height: <Text style={{ fontWeight: 'bold' }}>{initialHeight}</Text>{`\n`}
        Corrected height: <Text style={{ fontWeight: 'bold' }}>{correctedHeight}</Text>
      </Text>
    </View>
  );
}

const Stack = createNativeStackNavigator();

function MyStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="Home" component={HomeScreen} />
    </Stack.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <MyStack />
    </NavigationContainer>
  );
}

Snack or a link to a repository

https://snack.expo.dev/zxQpf-O7e?platform=ios

Screens version

3.20.0

React Native version

0.71.6

Platforms

iOS

JavaScript runtime

Hermes

Workflow

React Native (without Expo)

Architecture

Paper (Old Architecture)

Build type

Debug mode

Device

iOS simulator

Device model

iPhone 14 Pro

Acknowledgements

Yes

@github-actions github-actions bot added Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snack or repo is provided labels Jun 6, 2023
@dylancom dylancom changed the title Native Stack layout shift, initial render doesn't take header into account [iOS] Native Stack layout shift, initial render doesn't take header into account Jun 6, 2023
@dylancom
Copy link
Contributor Author

dylancom commented Jun 7, 2023

Temporary hack:
To prevent the layout from jumping, I currently calculate the screens height using:

const {height: WINDOW_HEIGHT} = Dimensions.get('window');
const headerHeight = useHeaderHeight();
const bottomTabBarHeight = useBottomTabBarHeight();
const screenHeight = WINDOW_HEIGHT - headerHeight - bottomTabBarHeight;

<View style={{ maxHeight: screenHeight }} />

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snack or repo is provided
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants