Skip to content

Commit

Permalink
fix(iOS): non-interactive screen while switching between bottom-tab a…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
tboba authored and ja1ns committed Oct 9, 2024
1 parent 60169d6 commit 8163afa
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 1 deletion.
86 changes: 86 additions & 0 deletions apps/src/tests/Test2252.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useState } from 'react';
import { Alert, Button, Text, View, Switch } from 'react-native';
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';

const RootStack = createNativeStackNavigator();
const BottomTab = createBottomTabNavigator();

function TabScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Test"
onPress={() => {
Alert.alert('Test');
}}
/>
<Switch
trackColor={{ false: '#767577', true: '#81b0ff' }}
thumbColor={'#f5dd4b'}
ios_backgroundColor="#3e3e3e"
onValueChange={() => {
Alert.alert('Test');
}}
/>
</View>
);
}

function TabsScreen() {
return (
<BottomTab.Navigator initialRouteName="tab">
<BottomTab.Screen name="tab" component={TabScreen} />
</BottomTab.Navigator>
);
}

export function RootStackNavigator() {
return (
<RootStack.Navigator
initialRouteName="tabNavigation"
screenOptions={{ headerShown: false }}>
<RootStack.Screen name="tabNavigation" component={TabsScreen} />
</RootStack.Navigator>
);
}

function LoginScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>No tabs</Text>
</View>
);
}

export function LoginStackNavigator() {
return (
<RootStack.Navigator
initialRouteName="login"
screenOptions={{ headerShown: false }}>
<RootStack.Screen name="login" component={LoginScreen} />
</RootStack.Navigator>
);
}

export default function App() {
const [showTabs, setShowTabs] = useState(true);
return (
<SafeAreaProvider>
<NavigationContainer key={showTabs ? 'a' : 'b'}>
{showTabs ? <RootStackNavigator /> : <LoginStackNavigator />}
</NavigationContainer>
<View style={{ marginBottom: 32 }}>
<Button
title="Toggle"
onPress={() => {
setShowTabs(!showTabs);
}}
/>
</View>
</SafeAreaProvider>
);
}
1 change: 1 addition & 0 deletions apps/src/tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,6 @@ export { default as Test2229 } from './Test2229';
export { default as Test2231 } from './Test2231';
export { default as Test2232 } from './Test2232';
export { default as Test2235 } from './Test2235';
export { default as Test2252 } from './Test2252';
export { default as TestScreenAnimation } from './TestScreenAnimation';
export { default as TestHeader } from './TestHeader';
2 changes: 1 addition & 1 deletion ios/RNSScreen.mm
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@ - (void)updateLayoutMetrics:(const react::LayoutMetrics &)layoutMetrics
_newLayoutMetrics = layoutMetrics;
_oldLayoutMetrics = oldLayoutMetrics;
UIViewController *parentVC = self.reactViewController.parentViewController;
if (parentVC != nil && ![parentVC isKindOfClass:[RNSNavigationController class]]) {
if (parentVC == nil || ![parentVC isKindOfClass:[RNSNavigationController class]]) {
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
}
// when screen is mounted under RNSNavigationController it's size is controller
Expand Down

0 comments on commit 8163afa

Please sign in to comment.