I tried to find a solution on my own, or at least similar problems with other people, but I failed.
This problem appeared after updating the react-native-reanimated to version 2.x. I need it to work with other components, so the option to roll back is not suitable.
The problem occurs only on android. Does anyone know why this might be?
My component code is presented below:
import PropTypes from 'prop-types';
import React, { useCallback, useMemo, useState } from 'react';
import TextInput from './TextInput';
import { View, StyleSheet } from 'react-native';
import { FAB, TouchableRipple } from 'react-native-paper';
import DateTimePickerModal from 'react-native-modal-datetime-picker';
import moment from 'moment';
import { colors } from '../../../styles/colors';
import { CalendarLinear } from '../../../config/images';
import { formatDate } from '../../../helpers';
import { typographySizes } from '../../../styles/typography.style';
import { em } from '../../../styles/sizes';
const minDate = new Date('1900-01-01');
const maxDate = new Date('2038-01-01');
const iconSize = typographySizes.small.fontSize;
const CalendarLinearIcon = () => (
<CalendarLinear width={iconSize} height={iconSize} fill={colors.muted_dark} />
);
const TextInputDate = (props) => {
let { value } = props;
const {
onChangeText,
mode = 'date',
min = minDate,
max = maxDate,
locale = 'ru-RU',
icon = true,
...rest
} = props;
value = formatDate(value);
const [visible, setVisible] = useState(false);
const showPicker = useCallback(() => {
setVisible(true);
}, []);
const hidePicker = useCallback(() => {
setVisible(false);
}, []);
const confirmPicker = useCallback(
(date) => {
const value = new moment(date).format('YYYY-MM-DD');
setVisible(false);
onChangeText(value);
},
[onChangeText]
);
const trailingIcon = useMemo(
() =>
(icon && (
<FAB small style={styles.calendarButton} icon={CalendarLinearIcon} />
)) ||
undefined,
[icon]
);
return (
<>
<DateTimePickerModal
isVisible={visible}
value={new Date(value)}
mode={mode}
minimumDate={min}
maximumDate={max}
locale={locale}
onConfirm={confirmPicker}
onCancel={hidePicker}
/>
<TouchableRipple
onPress={showPicker}
style={{ borderTopLeftRadius: em / 2, borderTopRightRadius: em / 2 }}
borderless>
<View>
<TextInput
{...rest}
keyboardType={'numeric'}
// onChangeText={onChange}
type={'date'}
editable={false}
value={value}
onFocus={showPicker}
trailingIcon={trailingIcon}
/>
<View style={StyleSheet.absoluteFill} />
</View>
</TouchableRipple>
</>
);
};
TextInputDate.propTypes = {
value: PropTypes.any.isRequired,
onChangeText: PropTypes.func.isRequired,
mode: PropTypes.oneOf(['date', 'time', 'datetime', 'countdown']),
min: PropTypes.instanceOf(Date),
max: PropTypes.instanceOf(Date),
locale: PropTypes.string,
};
const styles = {
calendarButton: {
backgroundColor: 'transparent',
shadowOpacity: 0,
shadowRadius: 0,
elevation: 0,
height: iconSize * 2,
width: iconSize * 2,
},
};
export default TextInputDate;
UPD1:
I found this only occurs on small screens. Apparently, a nested scrollable view is formed or something like that.
UPD2:
I tried to create a reproducible example in codesandbox but I get an error. I think this is a flaw in the platform. But this code can help reproduce this problem on your PC.
UPD3:
The problem cannot be the minimum or maximum date. Moreover, I do not use the time mode.
UPD4:
Apparently the issue has nothing to do with react-native-reanimated, it just coincided. I have reproduced the issue separately, without this library.
I also reported about the issue to the developers.
UPD5:
Thanks to the developer's answer, I ran additional tests and it turned out that the real reason for this behavior is in #react-native-community/datetimepicker.
The standard example from the documentation reproduces this behavior.
I have also reported the issue to other developers.
Looking at the props in the documentation, it says "Min Date. Does not work with 'time' picker on Android". Same for "Max Date."
The developer said there was no point in solving the problem... I agree with him, because this does not occur on real devices.
Related
I am new to react-native.
I am making a project in react-native with my android phone connected to my laptop at the USB port. When I run the project I see a blank screen on my phone. My phone is android version 9.
First I ran npm start and then I ran npm run android.
I ran adb -s device-name reverse tcp:8081 tcp:8081. Still the screen on my phone is blank.
This is my App.tsx file:
import "./i18n"
import React, { useState, useEffect, useRef } from "react"
import { YellowBox } from "react-native"
import { NavigationContainerRef } from "#react-navigation/native";
import { contains } from "ramda"
import { enableScreens } from "react-native-screens"
import { SafeAreaProvider, initialWindowSafeAreaInsets } from "react-native-safe-area-context";
import { RootNavigator, exitRoutes, setRootNavigation } from "./navigation"
import { useBackButtonHandler } from "./navigation/use-back-button-handler"
import { RootStore, RootStoreProvider, setupRootStore } from "./models/root-store"
import * as storage from "./utils/storage"
import getActiveRouteName from "./navigation/get-active-routename"
import { ThemeProvider } from 'react-native-elements';
import * as theme from 'theme';
import { AuthScreensWelcomeScreen } from './screens/auth-screens/welcome-screen';
enableScreens()
YellowBox.ignoreWarnings([
"componentWillMount is deprecated",
"componentWillReceiveProps is deprecated",
"Require cycle:",
])
const canExit = (routeName: string) => contains(routeName, exitRoutes)
export const NAVIGATION_PERSISTENCE_KEY = "NAVIGATION_STATE"
const App: React.FunctionComponent<{}> = () => {
const navigationRef = useRef<NavigationContainerRef>()
const [rootStore, setRootStore] = useState<RootStore | undefined>(undefined)
const [initialNavigationState, setInitialNavigationState] = useState()
const [isRestoringNavigationState, setIsRestoringNavigationState] = useState(true)
setRootNavigation(navigationRef)
useBackButtonHandler(navigationRef, canExit)
const routeNameRef = useRef()
const onNavigationStateChange = state => {
const previousRouteName = routeNameRef.current
const currentRouteName = getActiveRouteName(state)
if (previousRouteName !== currentRouteName) {
// track screens.
__DEV__ && console.tron.log(currentRouteName)
}
// Save the current route name for later comparision
routeNameRef.current = currentRouteName
// Clear the storage if we are navigating to auth stack
if ( ['register', 'login', 'forgotpassword'].includes(currentRouteName) ) {
storage.remove(NAVIGATION_PERSISTENCE_KEY);
} else {
// Persist navigation state to storage
storage.save(NAVIGATION_PERSISTENCE_KEY, state)
}
}
useEffect(() => {
(async () => {
setupRootStore().then(setRootStore)
})()
}, [])
useEffect(() => {
const restoreState = async () => {
try {
const state = await storage.load(NAVIGATION_PERSISTENCE_KEY)
if (state) {
setInitialNavigationState(state)
}
} finally {
setIsRestoringNavigationState(false)
}
}
if (isRestoringNavigationState) {
restoreState()
}
}, [isRestoringNavigationState])
if (!rootStore) {
return null
}
return (
<SafeAreaProvider initialSafeAreaInsets={initialWindowSafeAreaInsets}>
<AuthScreensWelcomeScreen />
</SafeAreaProvider>
)
}
export default App
Here is the welcome screen that should appear:
import React, { FunctionComponent, useState } from "react"
import { observer } from "mobx-react-lite"
import { Dimensions, Image } from "react-native"
import { Screen, Button } from "components"
import Carousel, { Pagination } from 'react-native-snap-carousel';
import { Block } from "components/block/block"
const { width: ScreenWidth } = Dimensions.get('screen');
import { NavigationProp, NavigationState } from "#react-navigation/native";
export interface AuthScreensWelcomeScreenProps {
navigation?: NavigationProp<Record<string, object>, string, NavigationState,
{}, {}>
}
export const AuthScreensWelcomeScreen:
FunctionComponent<AuthScreensWelcomeScreenProps> = observer((props) => {
const {
navigation
} = props;
const [activeSlide, setActiveSlide ] = useState(0);
const items = [
{ image: require('../../../assets/splash1.jpg') },
{ image: require('../../../assets/splash2.jpg') },
{ image: require('../../../assets/splash3.jpg') }
];
function renderItem ( { item, index } ) {
return (
<Image style={{ alignSelf: 'center', flex: 1, resizeMode: 'contain', width: ScreenWidth / 1.25 }} source={item.image}></Image>
)
}
return (
<Screen preset="fixed">
<Block flex>
<Carousel
sliderWidth={ScreenWidth}
itemWidth={ScreenWidth}
data={ items }
layout="default"
renderItem={ renderItem }
onSnapToItem={ index => { setActiveSlide( index ) } }/>
<Block>
<Pagination
activeDotIndex={activeSlide}
dotsLength={items.length}
dotStyle={{
width: 10,
height: 10
}}/>
</Block>
</Block>
<Block row my={20} space="evenly" px={20}>
<Button title="Continue" containerStyle={{ flex: 1 }} onPress={ ( ) => navigation.navigate('login') }/>
</Block>
</Screen>
)
})
Can anyone help?
If rootStore does not exist, then your render method returns null, so the page will be blank. Try this:
if (!rootStore) {
console.log('rootStore is not found');
return null
}
console.log('continue to render');
If you do not see continue to render printed out in your Metro server window, then that indicates rootStore was not found. Then you need to figure out why it doesn't exist, or at least show some kind of informative view to handle that case.
I replaced this:
<RootStoreProvider value={rootStore}>
<SafeAreaProvider initialSafeAreaInsets={initialWindowSafeAreaInsets}>
<ThemeProvider theme={theme}>
<RootNavigator
ref={navigationRef}
initialState={initialNavigationState}
onStateChange={onNavigationStateChange}
/>
</ThemeProvider>
</SafeAreaProvider>
</RootStoreProvider>
with
<SafeAreaProvider initialSafeAreaInsets={initialWindowSafeAreaInsets}>
<AuthScreensWelcomeScreen />
</SafeAreaProvider>
to get the blank white screen to go away. Please tell me if this is the correct way to do it.
CMD:
react-native init Test && react-native run-android
App.js:
export default class App extends Component {
render() {
new Function("person", "const { firstname } = person; alert(firstname);")({ firstname: "Test" });
}
}
Whenever the new function gets constructed and invoked, the app crashes stating: "SyntaxError: Unexpected token '{'. Expected an identifier name in const declaration" Only happens on Android.
Any help would be appreciated. Thanks!
React Native: v0.55.7
The react native documentation indicates that JavaScriptCore is generally used at runtime (V8 during debugging), but it's light on specifics as to how it is configured. One thing it does mention is that the native JavaScriptCore is used on iOS, while a different version is bundled with the app for user on Android.
Because Babel is used at compile time with react native to support ES5/ES6 features, it may be that the runtime is configured at a lower level of support. So when attempting to create code from a string at runtime, you may actually be running with a JavaScript interpreter that doesn't understand e.g., destructuring syntax.
You could try using Babel's transform at runtime to transpile your code:
import {transform} from 'babel-core';
export default class App extends Component {
render() {
const f = 'const { firstname } = person; alert(firstname);';
const result = transform(f, {
presets: ['es2015']
});
new Function("person", result.code)({ firstname: "Test" });
}
}
Can you create a const with a dynamic name? If it's possible, sorry about my lack of knowledge about that subject.
The error message said that a name to variable const is expected.
I hope it has been useful.
Best regards.
Try to change the style you create that function. In React Native is common to see arrow functions, that must be created outside your render method.
Note that your render method will be trigger every single time that your state changes. and it would be a waste of memory resources and unnecessary computing time
import React, {
Component
} from 'react';
import {
Text,
View,
StyleSheet
} from 'react-native';
export default class App extends Component {
//your custom function
myFunc = (param) => {
console.log(param)
return param
}
//your render method
render() {
const param = "Im a text"
//you could do this... i would never do that..
const myFuncInRender = () => { console.log('Im a stupid func')}
const myStupidFunc2 = new Function("person", "const { firstname } = person; alert(firstname);")({ firstname: "Test" });
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
{this.myFunc(param)/* HERE is where you call the func*/}
</Text>
</View>
);
}
} // end from Class
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
alignItems:'center',
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
I'm developing an app with React Native and I'm testing with my OnePlus 6 and it has a notch. The SafeAreaView is a solution for the iPhone X but for Android, it seems there is no solution.
How to solve this kind of issue?
Do something like
import { StyleSheet, Platform, StatusBar } from "react-native";
export default StyleSheet.create({
AndroidSafeArea: {
flex: 1,
backgroundColor: "white",
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0
}
});
And then In your App.js
import SafeViewAndroid from "./components/SafeViewAndroid";
<SafeAreaView style={SafeViewAndroid.AndroidSafeArea}>
<Layout screenProps={{ navigation: this.props.navigation }} /> //OR whatever you want to render
</SafeAreaView>
This should work good as get height will take care of the knotch in android device by calculating the statusBar height and it will arrange accordingly.
A work around I had to use recently:
GlobalStyles.js:
import { StyleSheet, Platform } from 'react-native';
export default StyleSheet.create({
droidSafeArea: {
flex: 1,
backgroundColor: npLBlue,
paddingTop: Platform.OS === 'android' ? 25 : 0
},
});
It is applied like so:
App.js
import GlobalStyles from './GlobalStyles';
import { SafeAreaView } from "react-native";
render() {
return (
<SafeAreaView style={GlobalStyles.droidSafeArea}>
//More controls and such
</SafeAreaView>
);
}
}
You'll probably need to adjust it a bit to fit whatever screen you're working on, but this got my header just below the icon strip at the top.
Late 2020 answer: For anyone stumbling across this issue themselves, they have added support for this.
Follow this documentation page
You could also create helper component with this style applied right away like this
import React from 'react';
import { StyleSheet, Platform, StatusBar, SafeAreaView } from 'react-native';
export default props => (
<SafeAreaView style={styles.AndroidSafeArea} {...props} >
{props.children}
</SafeAreaView>
);
const styles = StyleSheet.create({
AndroidSafeArea: {
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0
}
});
Make note that I also deleted unnecessary styles which breaks natural behavior of SafeAreaView which in my case broke styling.
As for use you simply use it like normal SafeAreaView:
import React from 'react';
import SafeAreaView from "src/Components/SafeAreaView";
render() {
return (
<SafeAreaView>
// Rest of your app
</SafeAreaView>
);
}
}
for more consistency import:
import { Platform, StatusBar } from "react-native";
and then use it like so:
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0
if you're seeing this in 2020 and you also need the web support with the Android and iOS, type this in your terminal.
expo install react-native-safe-area-context
this will install the updated safe area context.
Then import the following stuffs into your app.js
import { SafeAreaView, SafeAreaProvider} from "react-native-safe-area-context";
add <SafeAreaProvider> before all the tags in your main function in app.js, also remember to close it at the end.
and finally, instead of view, add SafeAreaView.
Read more at the official expo website : SafeAreaContext
Although the docs says it is relevant only for iOS, when I used React's SafeAreaView it acted differently on different screens on Android.
I managed to fix the problem by implementing my version of SafeAreaView:
import React from "react";
import { Platform, View, StatusBar } from "react-native";
import { GeneralStyle } from "../styles";
export function SaferAreaView({ children }) {
if (Platform.OS == "ios") {
return <SaferAreaView style={{ flex: 1 }}>{children}</SaferAreaView>;
}
if (Platform.OS == "android") {
return <View style={{flex: 1, paddingTop: StatusBar.currentHeight}}>{children}</View>;
}
}
This was tested on an old device (with hardware navigation) and new notch devices (with software navigation) - different screen sizes.
This is currently the best or easiest way to implement SafeAreaView on Android and ios for both vanilla RN and Expo.
import { SafeAreaView } from 'react-native-safe-area-context';
function SomeComponent() {
return (
<SafeAreaView>
<View />
</SafeAreaView>
);
}
1 - expo install expo-constants
2- and do like this for example
import React from "react";
import Constants from "expo-constants";
import { Text, StyleSheet, SafeAreaView, View } from "react-native";
export default function HeaderTabs({ style }) {
return (
<SafeAreaView style={[styles.screen, style]}>
<View style={[styles.view, style]}>
<Text>Hello this is status bar</Text>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
screen: {
paddingTop: Constants.statusBarHeight,
flex: 1,
},
view: {
flex: 1,
},
});
Instead of using Platform API, you can use expo constants.
npm i expo-constants
then import it in your component as
import Constants from "expo-constants"
and then in the styles you can use it like this
const styles = StyleSheet.create({
container: {
paddingTop: Constants.statusBarHeight
} });
To see all the properties of Constants console log it you will find some more useful things.
Well, I had the same problem. I solved this using this lib React Native Status Bar Height, and I recommend because it´s a piece of cake to use.
And if you are using style-components you can add the getStatusBarHeight() on your styles.js like I did on the example below:
import styled from 'styled-components/native';
import { getStatusBarHeight} from 'react-native-status-bar-height';
export const Background = styled.View`
flex:1;
background:#131313;
margin-top: ${getStatusBarHeight()};
`
In the SafeAreaView Docs was told:
It is currently only applicable to iOS devices with iOS version 11 or later.
So now I definitely use it in my project but I use Platform to recognize device platform and for Android, I make a manual safe area for the status bar.
you can use react-native-device-info for device info and apply styling also with a notch
I used StatusBar from react-native instead of expo-status-bar and this worked for me on my OnePlus as well as other Android devices.
import { StatusBar } from 'react-native';
Expo solution(docs - android only):
import { setStatusBarTranslucent } from 'expo-status-bar';
Then in the component you can use useEffect hook:
useEffect(() => {
setStatusBarTranslucent(false)
},[])
for iOS you can use the <SafeAreaView> component from react-native.
ENRICO SECCO was right (i cant comment due to my stackoverflow reputation lol)! any safeareaview thingy doesn't work for me as well, so i get around with
import { getStatusBarHeight} from 'react-native-status-bar-height';
here how execute it, keep in mind that this is in my app.js, where i put all my stack.navigator + bottomtab.navigator
export default function App() {
//IGNORE ALL OF THIS, JUMP TO THE RETURN() FUNCTION!
const [appIsReady, setAppIsReady] = useState(false);
useEffect(() => {
async function prepare() {
try {
await SplashScreen.preventAutoHideAsync();
await Font.loadAsync(AntDesign.font);
await Font.loadAsync({
'Montserrat-Bold': require('./assets/fonts/Montserrat-Bold.ttf'),
'Montserrat-Regular': require('./assets/fonts/Montserrat-Regular.ttf'),
'Montserrat-Light': require('./assets/fonts/Montserrat-Light.ttf'),
});
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (e) {
console.warn(e);
} finally {
// Tell the application to render
setAppIsReady(true);
}
}
prepare();
}, []);
const onLayoutRootView = useCallback(async () => {
if (appIsReady) {
await SplashScreen.hideAsync();
}
}, [appIsReady]);
if (!appIsReady) {
return null;
}
return (
//HERE!
<NavigationContainer>
<View style = {{
flex: 1, <- TO MAKE IT FULL SCREEN (PLEASE DELETE THIS)
marginTop: getStatusBarHeight(), <- TO PUSH IT DOWN FROM OFF SCREEN, MINE RAN OFF TO THE TOP LMAO (PLEASE DELETE THIS)
}} onLayout={onLayoutRootView}>
<Tabs/>
</View>
</NavigationContainer>
);
}
This is possibly just an Android 6.0 bug. I tested the snack below in Android 5.1.1 and Android 7.0 and it didn't happen there.
I am trying to do an autocomplete whenever the user types "#". I successfully do this, however once I backspace a couple times, the value on the native side becomes some value I never had before. I have simplified the case to this code below:
Please try the snack here - https://snack.expo.io/#noitsnack/what-the-heck---autocomplete-then-backspace-bug OR copy and paste the code into a new react-native init project. I tested in RN 0.51 and RN 0.54.
Please then type Hi #
You will see it autocompletes to Hi #foobar.
Then backspace once and it properly is now Hi #fooba.
Backspace again, and now it is Hi #foHi (this is the bug, it should be Hi #foob)
This is a controlled input. I have no idea why it's turning into Hi #foHi on second backspace. If I blur then come after step 3 it doesn't come back.
I tried on two other devices, Android 7.0 and Android 5.1.1, and this bug was not there. It only happened on my Android 6.0. I think this is a OS dependent bug. Does anyone have ideas on what is actually going on? That will help me on how to work around this on all devices.
Is this really a bug on RN side?
I recorded a screencast of this behavior here in HD:
https://gfycat.com/RectangularAltruisticEuropeanfiresalamander
Here is a GIF:
The code (copied from the expo snack):
import React, { Component } from 'react';
import { StyleSheet, Text, View, TextInput } from 'react-native'
class FieldMentionable extends Component<Props, State> {
state = {
value: ''
}
render() {
const { value } = this.state;
return <TextInput onChange={this.handleChange} value={value} multiline />
}
handleChange = ({ nativeEvent:{ text }}) => {
const { value } = this.state;
if (text.endsWith(' #')) this.setState(() => ({ value:text + 'foobar' }));
else this.setState(() => ({ value:text }));
}
handleRef = el => this.input = el;
}
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<FieldMentionable />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 100,
backgroundColor: '#F5FCFF',
}
});
This is a bug on and its root issue has been filed here - https://github.com/facebook/react-native/issues/19085
I am using this library https://reactnavigation.org/docs/intro/ to build android by react-native. I can make the navigation happens on android device but how I can make the screen slide in from the right and fade in from the left. It seems that this behaviour happens on iOS device but not in Android. Is there any animation configuration for android app?
Please see below animation. This is recorded in iOS.
Starting from : "#react-navigation/native": "^5.5.1",
import {createStackNavigator, TransitionPresets} from '#react-navigation/stack';
const TransitionScreenOptions = {
...TransitionPresets.SlideFromRightIOS, // This is where the transition happens
};
const CreditStack = createStackNavigator();
function CreditStackScreen() {
return (
<CreditStack.Navigator screenOptions={TransitionScreenOptions}> // Don't forget the screen options
<CreditStack.Screen
name="Credit"
component={HomeScreen}
options={headerWithLogo}
/>
<HomeStack.Screen
name="WorkerDetails"
component={WorkerDetails}
options={headerWithLogoAndBackBtn}
/>
</CreditStack.Navigator>
);
}
You can watch this video to understand more:
https://www.youtube.com/watch?v=PvjV96CNPqM&ab_channel=UnsureProgrammer
You should use transitionConfig to override default screen transitions as written on this page.
Unfortunately there is no example provided how that function works but you can find some examples in this file: \react-navigation\lib\views\CardStackStyleInterpolator.js
So your code should look like this:
const navigator = StackNavigator(scenes, {
transitionConfig: () => ({
screenInterpolator: sceneProps => {
const { layout, position, scene } = sceneProps;
const { index } = scene;
const translateX = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [layout.initWidth, 0, 0]
});
const opacity = position.interpolate({
inputRange: [
index - 1,
index - 0.99,
index,
index + 0.99,
index + 1
],
outputRange: [0, 1, 1, 0.3, 0]
});
return { opacity, transform: [{ translateX }] };
}
})
});
For StackNavigatoin 6.x.x
Just import
import { TransitionPresets } from '#react-navigation/stack';
Then create a config:
const screenOptionStyle = {
// headerShown: false,
...TransitionPresets.SlideFromRightIOS,
};
And finally just assign them to the Stack Navigator Screen Options:
<Stack.Navigator
screenOptions={screenOptionStyle}
>
<Stack.Screen
...
...
All the above answers are correct, but the solutions work ONLY if you are using createStackNavigator, and not if you are using createNativeStackNavigator; unfortunatelly, if you are following the get started section from react-navigation's docs, you will end up using the latter.
Here you can find a SO question speaking about the differences between the two, but the most relevant one for this questions is that many of the options that your can pass to the former (such as transitionConfig), cannot be passed to the latter.
If you are using createNativeStackNavigator this is how you can do it:
import { createNativeStackNavigator } from '#react-navigation/native-stack'
const StackNavigator = createNativeStackNavigator()
const MyNativeStackNavigator = () =>{
return <StackNavigator.Navigation
screenOptions={{
animation: 'slide_from_right', //<-- this is what will do the trick
presentation: 'card',
}}
>
{routes}
</StackNavigator.Navigator>
}
you need to import StackViewTransitionConfigs from 'react-navigation-stack'
then, override the transitionConfing function.
const myStack = createStackNavigator({
Screen1,
Screen2,
Screen3
},{
transitionConfig: () => StackViewTransitionConfigs.SlideFromRightIOS
}
On #react-navigation/stack component version, the way to do a slide from the right animation is:
<Stack.Navigator
screenOptions={{
cardStyleInterpolator: ({index, current, next, layouts: {screen}}) => {
const translateX = current.progress.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [screen.width, 0, 0],
});
const opacity = next?.progress.interpolate({
inputRange: [0, 1, 2],
outputRange: [1, 0, 0],
});
return {cardStyle: {opacity, transform: [{translateX}]}};
},
}}>
<Stack.Screen name="MainScreen" component={MainScreen} />
...
</Stack.Navigator>
Better you can use the react native navigation for this. You can configure your screen using configureScene method. Inside that method use Navigator.SceneConfigs for animating screen. It's work for both android and iOS.
You can get useful information from index.d.ts file, find the export interface TransitionConfig , then press 'Ctrl' & left_click on NavigationTransitionSpec and NavigationSceneRendererProps, then you can get everything you want.