23

How do I set the height a React Navigation modal view so once it has appeared it will only cover about half of the screen from the bottom up, and the view below remains visible?

Update: I'm trying to create a ux flow similar to the App Store purchase modal, where some kind of StackNavigator is nested in a modal that fills the bottom half of the screen.

App Store modal

matthew
  • 2,156
  • 5
  • 22
  • 38

4 Answers4

30

In your stacknavigator you can set these options:

  mode: 'modal',
    headerMode: 'none',
    cardStyle:{
      backgroundColor:"transparent",
      opacity:0.99
  }

And in your modal screen:

class ModalScreen extends React.Component {

  render() {
    return (
      <View style={{ flex: 1 ,flexDirection: 'column', justifyContent: 'flex-end'}}>
          <View style={{ height: "50%" ,width: '100%', backgroundColor:"#fff", justifyContent:"center"}}>
            <Text>Testing a modal with transparent background</Text>
          </View>
      </View>
    );
  }
}

Also you can refer to this expo snack https://snack.expo.io/@yannerio/modal that I've created to show how it works, or you could use React Native Modal

Yanci Nerio
  • 784
  • 9
  • 12
  • Thanks Yanci, this works for a standard modal, but if I nest a StackNavigator inside a modal the transparency becomes black. Take a look: https://snack.expo.io/@mattvick/navigation-playground Can you explain how the `opacity: 0.99` fixes the transparency on the standard modal? – matthew Feb 26 '18 at 19:27
  • I opened that snack and I can't reproduce the transparency becoming black, I can navigate into the signer modal, then the unlock and finally the sign screen and everything looks fine, the transparency is there. – Yanci Nerio Feb 26 '18 at 19:57
  • You're right that it works with Android (https://i.stack.imgur.com/VFaOX.png), but not with iOS (https://i.stack.imgur.com/uhzMp.png). I've tested using both appetize.io and running on an iPhone – matthew Feb 26 '18 at 20:07
  • Could you use **Platform** to determinate which is the current Platform and set the opacity that works for each one? sadly I cannot test on IOS right now. I can see there is transparency there but is dark – Yanci Nerio Feb 26 '18 at 20:11
  • Look at this maybe it helps https://github.com/react-navigation/react-navigation/issues/2713 – Yanci Nerio Feb 26 '18 at 20:37
  • 1
    Thanks Yanci, setting `transitionConfig` on the nested StackNavigator as suggested in issue 2713 fixes the transparency in iOS and Andriod still works :) FYI `opacity: 1` also works – matthew Feb 26 '18 at 23:42
  • @YanciNerio This is not working in version 3.x, can you please confirm? – Romit Kumar Nov 22 '18 at 07:39
  • 2
    @RomitKumar add this property `transparentCard: true` to make it work with v3.x here you can see it working https://snack.expo.io/@yannerio/ashamed-truffle – Yanci Nerio Nov 24 '18 at 04:43
  • 3
    @YanciNerio opacity of 0.5 in iOS is changing the opacity of homescreen too, change this to 1 and then the same issue will arise, the modal screen's background will be white instead of transparent – Romit Kumar Nov 24 '18 at 06:37
  • @YanciNerio is it possible to set height in react-native modal? – Reza Sam Sep 17 '19 at 13:03
  • I took Yanci's code and modified it to work for me, by using `transparentCard: true`. Note this property is needed on the RootStack. HTH. https://snack.expo.io/@alexweber1/transparent-background-modal-test – Alex W Jul 09 '20 at 21:50
19

Here's an example of how to achieve this in react-navigation v3.x:

demo

App Container

const TestRootStack = createStackNavigator(
  {
    TestRoot: TestRootScreen,
    TestModal: {
      screen: TestModalScreen,
      navigationOptions: {
        /**
         * Distance from top to register swipe to dismiss modal gesture. Default (135)
         * https://reactnavigation.org/docs/en/stack-navigator.html#gestureresponsedistance
         */
        gestureResponseDistance: { vertical: 1000 }, // default is 135 },
      },
    },
  },
  {
    headerMode: 'none',
    mode: 'modal',
    transparentCard: true,
  },
);

const AppContainer = createAppContainer(TestRootStack);

Root Screen

class TestRootScreen extends React.Component {
  render() {
    return (
      <SafeAreaView style={styles.container}>
        <Button title="Show Modal" onPress={() => this.props.navigation.navigate('TestModal')} />
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'blue',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Modal Screen

class TestModalScreen extends React.Component {
  render() {
    return (
      <SafeAreaView style={styles.container}>
        <View style={styles.innerContainer} />
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'transparent',
    justifyContent: 'flex-end',
  },
  innerContainer: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    top: 100,
    backgroundColor: 'red',
  },
});

GollyJer
  • 23,857
  • 16
  • 106
  • 174
desmond
  • 560
  • 7
  • 8
2

For react-navigation v3.x you can use the prop transparentCard: true, you can see more details here: https://stackoverflow.com/a/55598127/6673414

Cristian Mora
  • 1,813
  • 2
  • 19
  • 27
2

if you want to use react native Modal you can make parent view transparent and add a view at the bottom

<Modal
      animationType="slide"
      transparent={true}
      visible={props.visible}
    >
     <View
          style={{
             backgroundColor:'transparent',
             flex:1,
             justifyContent:'flex-end'
                 }}>
          <View
               style={{
                   backgroundColor:'green',
                   height:'20%'
                 }}>
               <Text>Hello World!</Text>
               <TouchableHighlight
                    onPress={props.closeModal}>
                     <Text>Hide Modal</Text>
               </TouchableHighlight>
          </View>
    </View>
 </Modal>
Reza Sam
  • 1,264
  • 2
  • 14
  • 29