-
-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## 📜 Description Fixed incorrect paddings when android rotation happens. ## 💡 Motivation and Context The fix contains from 2 main points: - the bottom padding is getting kind of frozen because we don't get `ApplyWindowInsets` when rotation happened, so at the bottom of the screen we have our old padding which is equal to navBar height. To fix that we need to `requestApplyInsets`. But simple request is not enough for some reasons - our listener will not be fired, so we need to reattach listenere and request insets again, after that we get: <img width="712" alt="Screenshot 2024-08-19 at 11 07 00" src="https://github.com/user-attachments/assets/47b68bea-4a12-471d-b509-05ae7b37e47f"> - to fix empty spacing from left side and resolve all conflicts with `react-native-safe-area-context` we need to apply correct left and right paddings (depends on rotation angle). We need to take navBarInsets and apply insets accordingly. After that we get properly resized view: <img width="711" alt="Screenshot 2024-08-19 at 11 01 39" src="https://github.com/user-attachments/assets/acedcc2e-69e1-4231-9240-b2527e1bedf1"> To be sure it doesn't get broken in future I added e2e tests. On iOS I had empty spaces and I fixed them by stretching `background` element to all edges. Such fix makes it more complicated to notice a regression for human on Android (because we will not have empty spaces in tab bar), but all content will be shifted so `e2e` will spot a regression. > using `background` element helps us to get cross-platform UI 🙃 Closes #547 ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### E2E - added e2e tests with rotation; ### JS - added `BottomTabBar` example; ### Android - override `onConfigurationChanged` method; - create `reApplyWindowInsets` method; - use `reApplyWindowInsets` in `onConfigurationChanged` and `forceStatusBarTranslucent`; - apply correct left/right insets based on `navBar` insets. ## 🤔 How Has This Been Tested? Tested manually on Pixel 2 API 30. ## 📸 Screenshots (if appropriate): |Before|After| |-------|-----| |<img width="711" alt="Screenshot 2024-08-19 at 11 03 20" src="https://github.com/user-attachments/assets/ec3a2068-d5cd-4258-a9d6-8d80f319a28c">|<img width="711" alt="Screenshot 2024-08-19 at 11 01 39" src="https://github.com/user-attachments/assets/acedcc2e-69e1-4231-9240-b2527e1bedf1">| ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
- Loading branch information
1 parent
2c460d3
commit 0d7ef43
Showing
35 changed files
with
238 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; | ||
import { createNativeStackNavigator } from "@react-navigation/native-stack"; | ||
import * as React from "react"; | ||
import { StyleSheet, Text, View } from "react-native"; | ||
|
||
import KeyboardAnimation from "../../screens/Examples/KeyboardAnimation"; | ||
|
||
const Tab = createBottomTabNavigator(); | ||
const HomeStack = createNativeStackNavigator(); | ||
const SettingsStack = createNativeStackNavigator(); | ||
|
||
const HomeStackScreens = () => { | ||
return ( | ||
<HomeStack.Navigator> | ||
<HomeStack.Screen component={KeyboardAnimation} name="Home" /> | ||
</HomeStack.Navigator> | ||
); | ||
}; | ||
|
||
const SettingsStackScreens = () => { | ||
return ( | ||
<SettingsStack.Navigator> | ||
<SettingsStack.Screen component={KeyboardAnimation} name="Settings" /> | ||
</SettingsStack.Navigator> | ||
); | ||
}; | ||
|
||
export default function BottomTabBar() { | ||
return ( | ||
<Tab.Navigator | ||
detachInactiveScreens={true} | ||
screenOptions={({ route }) => ({ | ||
tabBarBackground: () => <View style={styles.tabBarBackground} />, | ||
tabBarIcon: () => | ||
route.name === "HomeStack" ? ( | ||
<Text style={styles.icon}>🏠</Text> | ||
) : ( | ||
<Text style={styles.icon}>⚙️</Text> | ||
), | ||
tabBarLabel: () => | ||
route.name === "HomeStack" ? ( | ||
<Text style={styles.label}>Home</Text> | ||
) : ( | ||
<Text style={styles.label}>Settings</Text> | ||
), | ||
headerShown: false, | ||
})} | ||
> | ||
<Tab.Screen component={HomeStackScreens} name="HomeStack" /> | ||
<Tab.Screen component={SettingsStackScreens} name="SettingsStack" /> | ||
</Tab.Navigator> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
icon: { | ||
color: "white", | ||
fontSize: 20, | ||
}, | ||
label: { | ||
color: "white", | ||
marginHorizontal: 20, | ||
}, | ||
tabBarBackground: { | ||
backgroundColor: "#2c2c2c", | ||
width: "100%", | ||
height: "100%", | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { expectBitmapsToBeEqual } from "./asserts"; | ||
import { | ||
closeKeyboard, | ||
scrollDownUntilElementIsVisible, | ||
waitAndTap, | ||
waitForExpect, | ||
} from "./helpers"; | ||
|
||
describe("Bottom tab bar", () => { | ||
it("should navigate to `Bottom tab bar` screen", async () => { | ||
await scrollDownUntilElementIsVisible("main_scroll_view", "bottom_tab_bar"); | ||
await waitAndTap("bottom_tab_bar"); | ||
}); | ||
|
||
it("should have expected state in portrait mode", async () => { | ||
await waitForExpect(async () => { | ||
await expectBitmapsToBeEqual("BottomTabBarPortrait", 0.25); | ||
}); | ||
}); | ||
|
||
it("should have expected state in landscape mode", async () => { | ||
await device.setOrientation("landscape"); | ||
await waitForExpect(async () => { | ||
await expectBitmapsToBeEqual("BottomTabBarLandscape"); | ||
}); | ||
}); | ||
|
||
it("should have expected state in portrait mode after rotation", async () => { | ||
await device.setOrientation("portrait"); | ||
await waitForExpect(async () => { | ||
await expectBitmapsToBeEqual("BottomTabBarPortraitAgain"); | ||
}); | ||
}); | ||
|
||
it("should have expected state when keyboard open", async () => { | ||
await waitAndTap("keyboard_animation_text_input"); | ||
await waitForExpect(async () => { | ||
await expectBitmapsToBeEqual("BottomTabBarKeyboardIsShown"); | ||
}); | ||
}); | ||
|
||
it("should have expected state when emoji keyboard closed", async () => { | ||
await closeKeyboard("keyboard_animation_text_input"); | ||
await waitForExpect(async () => { | ||
await expectBitmapsToBeEqual("BottomTabBarKeyboardIsHidden"); | ||
}); | ||
}); | ||
}); |
Binary file added
BIN
+36.6 KB
e2e/kit/assets/android/e2e_emulator_28/BottomTabBarKeyboardIsHidden.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+78.3 KB
e2e/kit/assets/android/e2e_emulator_28/BottomTabBarKeyboardIsShown.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+41.9 KB
e2e/kit/assets/android/e2e_emulator_31/BottomTabBarKeyboardIsHidden.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+96.1 KB
e2e/kit/assets/android/e2e_emulator_31/BottomTabBarKeyboardIsShown.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; | ||
import { createNativeStackNavigator } from "@react-navigation/native-stack"; | ||
import * as React from "react"; | ||
import { StyleSheet, Text, View } from "react-native"; | ||
|
||
import KeyboardAnimation from "../../screens/Examples/KeyboardAnimation"; | ||
|
||
const Tab = createBottomTabNavigator(); | ||
const HomeStack = createNativeStackNavigator(); | ||
const SettingsStack = createNativeStackNavigator(); | ||
|
||
const HomeStackScreens = () => { | ||
return ( | ||
<HomeStack.Navigator> | ||
<HomeStack.Screen component={KeyboardAnimation} name="Home" /> | ||
</HomeStack.Navigator> | ||
); | ||
}; | ||
|
||
const SettingsStackScreens = () => { | ||
return ( | ||
<SettingsStack.Navigator> | ||
<SettingsStack.Screen component={KeyboardAnimation} name="Settings" /> | ||
</SettingsStack.Navigator> | ||
); | ||
}; | ||
|
||
export default function BottomTabBar() { | ||
return ( | ||
<Tab.Navigator | ||
detachInactiveScreens={true} | ||
screenOptions={({ route }) => ({ | ||
tabBarBackground: () => <View style={styles.tabBarBackground} />, | ||
tabBarIcon: () => | ||
route.name === "HomeStack" ? ( | ||
<Text style={styles.icon}>🏠</Text> | ||
) : ( | ||
<Text style={styles.icon}>⚙️</Text> | ||
), | ||
tabBarLabel: () => | ||
route.name === "HomeStack" ? ( | ||
<Text style={styles.label}>Home</Text> | ||
) : ( | ||
<Text style={styles.label}>Settings</Text> | ||
), | ||
headerShown: false, | ||
})} | ||
> | ||
<Tab.Screen component={HomeStackScreens} name="HomeStack" /> | ||
<Tab.Screen component={SettingsStackScreens} name="SettingsStack" /> | ||
</Tab.Navigator> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
icon: { | ||
color: "white", | ||
fontSize: 20, | ||
}, | ||
label: { | ||
color: "white", | ||
marginHorizontal: 20, | ||
}, | ||
tabBarBackground: { | ||
backgroundColor: "#2c2c2c", | ||
width: "100%", | ||
height: "100%", | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters