Closed MatLish00010 closed 1 year ago
The Modal presentation in iOS is iOS only. you can use JS Stack https://expo.github.io/router/docs/migration/react-navigation/native-stack and set the screen option:
<JsStack.Screen
key={name}
name={name}
options={{
...TransitionPresets.ModalPresentationIOS,
presentation: 'modal'
}}
/>
To clarify, use JS stack:
import {
// Import the creation function
createStackNavigator,
// Import the types
StackNavigationOptions,
} from "@react-navigation/stack";
import { withLayoutContext } from "expo-router";
const { Navigator } = createStackNavigator();
// This can be used like `<JsStack />`
export const JsStack = withLayoutContext<
StackNavigationOptions,
typeof Navigator
>(Navigator);
Then
import { TransitionPresets } from '@react-navigation/stack';
// Later ...
<JsStack name="..." options={{
...TransitionPresets.ModalPresentationIOS,
presentation: 'modal'
}}>
Any chance this could be implemented directly with Expo-Router, without using JsStack?
When using JsStack, one has to use different option names (animationEnabled
vs animation
, …) and has some glitches like different letter spacing for the header title, at least with our app.
It would be better to be able use it with just presentation: "modal", rather than weird workaround
@EvanBacon how can I do it with Expo v2 and SDK 49, I'm getting dependency conflict
...TransitionPresets.ModalPresentationIOS,
The modal does not close on Android when I swipe it down
It would be better to be able use it with just presentation: "modal", rather than weird workaround
yes, agree. @EvanBacon any chance for this?
@EvanBacon the solution you provide, do not make the android have the same result of IOS, it's keep the Android Version having the same result as before, actually I'm in expo router v2 and expo 49
"expo-router": "2.0.0"
"react": "18.2.0",
"react-native": "0.72.4",
I'm using Expo Go to test it in a physical iPhone 7 with IOS 15.7.6, and it's working fine I'm also using a physical Samsung Galaxy S20 with Android 13 and One UI 5.1 to test in Android with Expo Go
My expo go version on android is 2.29.8 my expo go client version on IOS is 1017565
that's my code piece in my app/_layout.tsx
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<JsStack.Screen
name="filters"
options={{
...TransitionPresets.ModalPresentationIOS,
presentation: "modal",
}}
/>
</Stack>
and that's the code I'm using to provide the JsStack:
import {
// Import the creation function
createStackNavigator,
// Import the types
StackNavigationOptions
} from '@react-navigation/stack'
import { withLayoutContext } from 'expo-router'
const { Navigator } = createStackNavigator()
// This can be used like `<JsStack />`
export const JsStack = withLayoutContext<
StackNavigationOptions,
typeof Navigator
>(Navigator)
the same code you provide above I'm open to help solve that issue, appreciate it
Hi @EvanBacon, I'm experiencing the exact same problem @DarlonHenrique mentioned using expo-router v2. Is there any solutions ?
...TransitionPresets.ModalPresentationIOS,
The modal does not close on Android when I swipe it down
If you add gestureEnabled: true to the options the swipe down works for me on Android
@EvanBacon We have used provided example in a typescript project and we get a type error for the withLayoutContext function that it expects 4 type arguments not 2, it works if the ignore the typescript error but it is not a really nice solution imo. So it would be great if it would be possible to have the modal work on android with expo-router directly so we could skip this workaround💪
Hi, I'm with the same issue. I have tried to use presentation: modal
in the same stack and in another stack, but I still have the same result. Any updates?
I don't think pinging the guy again and again is going to help get this issue resolved.
From the Material UI documentation, it looks like Android simply doesn't support swipeable full-screen dialogs the same way iOS has.
So there simply isn't any solution other than to implement your own with the JSStack navigator, like shown already. More information can be found here.
@EvanBacon We have used provided example in a typescript project and we get a type error for the withLayoutContext function that it expects 4 type arguments not 2, it works if the ignore the typescript error but it is not a really nice solution imo. So it would be great if it would be possible to have the modal work on android with expo-router directly so we could skip this workaround💪
Reference the implementation of withLayoutContext. You can customise MaterialBottomTabs
like this to use with Expo Router:
import {
createMaterialBottomTabNavigator,
MaterialBottomTabNavigationEventMap,
MaterialBottomTabNavigationOptions,
} from 'react-native-paper/react-navigation'
import { NavigationState, ParamListBase } from '@react-navigation/native'
import { withLayoutContext } from 'expo-router'
const { Navigator } = createMaterialBottomTabNavigator()
export const MaterialBottomTabs = withLayoutContext<
MaterialBottomTabNavigationOptions,
typeof Navigator,
NavigationState<ParamListBase>,
MaterialBottomTabNavigationEventMap
>(Navigator)
I want to use native stack not js stack, any solution?
@fukemy Android does not support modal screens, so no. The only solution is to emulate the iOS behavior with JS stack. Check my comment above.
Is this still so for expo router 3?
StackNavigationOptions
Is this still so for expo router 3?
I think so
@EvanBacon the solution you provide, do not make the android have the same result of IOS, it's keep the Android Version having the same result as before, actually I'm in expo router v2 and expo 49
"expo-router": "2.0.0" "react": "18.2.0", "react-native": "0.72.4",
I'm using Expo Go to test it in a physical iPhone 7 with IOS 15.7.6, and it's working fine I'm also using a physical Samsung Galaxy S20 with Android 13 and One UI 5.1 to test in Android with Expo Go
My expo go version on android is 2.29.8 my expo go client version on IOS is 1017565
that's my code piece in my app/_layout.tsx
<Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> <JsStack.Screen name="filters" options={{ ...TransitionPresets.ModalPresentationIOS, presentation: "modal", }} /> </Stack>
and that's the code I'm using to provide the JsStack:
import { // Import the creation function createStackNavigator, // Import the types StackNavigationOptions } from '@react-navigation/stack' import { withLayoutContext } from 'expo-router' const { Navigator } = createStackNavigator() // This can be used like `<JsStack />` export const JsStack = withLayoutContext< StackNavigationOptions, typeof Navigator >(Navigator)
the same code you provide above I'm open to help solve that issue, appreciate it
Any luck ? I am also having the same issue.
@EvanBacon the solution you provide, do not make the android have the same result of IOS, it's keep the Android Version having the same result as before, actually I'm in expo router v2 and expo 49
"expo-router": "2.0.0" "react": "18.2.0", "react-native": "0.72.4",
I'm using Expo Go to test it in a physical iPhone 7 with IOS 15.7.6, and it's working fine I'm also using a physical Samsung Galaxy S20 with Android 13 and One UI 5.1 to test in Android with Expo Go
My expo go version on android is 2.29.8 my expo go client version on IOS is 1017565
that's my code piece in my app/_layout.tsx
<Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> <JsStack.Screen name="filters" options={{ ...TransitionPresets.ModalPresentationIOS, presentation: "modal", }} /> </Stack>
and that's the code I'm using to provide the JsStack:
import { // Import the creation function createStackNavigator, // Import the types StackNavigationOptions } from '@react-navigation/stack' import { withLayoutContext } from 'expo-router' const { Navigator } = createStackNavigator() // This can be used like `<JsStack />` export const JsStack = withLayoutContext< StackNavigationOptions, typeof Navigator >(Navigator)
the same code you provide above I'm open to help solve that issue, appreciate it
Try changing your app/_layout.tsx:
<JsStack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<JsStack.Screen
name="filters"
options={{
...TransitionPresets.ModalPresentationIOS,
presentation: "modal",
gestureEnabled: true,
}}
/>
</JsStack>
This worked for me
@EvanBacon We have used provided example in a typescript project and we get a type error for the withLayoutContext function that it expects 4 type arguments not 2, it works if the ignore the typescript error but it is not a really nice solution imo. So it would be great if it would be possible to have the modal work on android with expo-router directly so we could skip this workaround💪
import { Stack, withLayoutContext } from "expo-router";
import {
createStackNavigator,
StackNavigationEventMap,
StackNavigationOptions,
TransitionPresets,
} from "@react-navigation/stack";
import { ParamListBase, StackNavigationState } from "@react-navigation/native";
const { Navigator } = createStackNavigator();
export const JsStack = withLayoutContext<
StackNavigationOptions,
typeof Navigator,
StackNavigationState
(Navigator);
The expo team should update the docs then, i´ve been trying to see how to solve it just because the docs say it supports android
(property) presentation?: "modal" | "transparentModal" | "containedModal" | "containedTransparentModal" | "fullScreenModal" | "formSheet" | "card" | undefined
How should the screen be presented.
Supported values:
"card": the new screen will be pushed onto a stack, which means the default animation will be slide from the side on iOS, the animation on Android will vary depending on the OS version and theme.
"modal": the new screen will be presented modally. this also allows for a nested stack to be rendered inside the screen.
"transparentModal": the new screen will be presented modally, but in addition, the previous screen will stay so that the content below can still be seen if the screen has translucent background.
"containedModal": will use "UIModalPresentationCurrentContext" modal style on iOS and will fallback to "modal" on Android.
"containedTransparentModal": will use "UIModalPresentationOverCurrentContext" modal style on iOS and will fallback to "transparentModal" on Android.
"fullScreenModal": will use "UIModalPresentationFullScreen" modal style on iOS and will fallback to "modal" on Android.
"formSheet": will use "UIModalPresentationFormSheet" modal style on iOS and will fallback to "modal" on Android.
Only supported on iOS and Android.
@EvanBacon We have used provided example in a typescript project and we get a type error for the withLayoutContext function that it expects 4 type arguments not 2, it works if the ignore the typescript error but it is not a really nice solution imo. So it would be great if it would be possible to have the modal work on android with expo-router directly so we could skip this workaround💪
- you can type it like this below, it's working for me
import { Stack, withLayoutContext } from "expo-router"; import { createStackNavigator, StackNavigationEventMap, StackNavigationOptions, TransitionPresets, } from "@react-navigation/stack"; import { ParamListBase, StackNavigationState } from "@react-navigation/native"; const { Navigator } = createStackNavigator(); export const JsStack = withLayoutContext< StackNavigationOptions, typeof Navigator, StackNavigationState<ParamListBase>, StackNavigationEventMap >(Navigator);
I was getting the same typescript error and you literally saved me with that! Thanks, man!
You should update the expo router docs. It is really misleading. It mentioned that android is supported when clearly it's not.. and instead developers lead to using this workaround instead.
someone created an iOS Modal Sheet Animation for Android. It may be very useful and people may be interested. https://github.com/ElSierra/ios-sheet-for-android-react-native
I would love to know what you guys think about it.
We tried using the JS Stack solution, but our modal is around 3 nested navigators deep.. The IOS modal displays over all of the nested navigator headers but the JSStack modal only displays within the parent stack..
Has anyone encountered / solved this?
Thanks to everyone!. Working fine on my end.
Specifically to: @EvanBacon and @tittobreno
Which package manager are you using? (Yarn is recommended)
yarn
Summary
On android modal screen looks like simplify screen, but on IoS everything is fine
Minimal reproducible example
` <Stack.Screen mode="modal" name="myModal" screenOptions={{headerShown: true, presentation: 'modal'}}
/>
`