Close react native modal by clicking on overlay?

前端 未结 13 654
梦如初夏
梦如初夏 2020-12-23 14:27

Is it possible to close react native modal by clicking on overlay when transparent option is true? Documentation doesn\'t provide anything about it

相关标签:
13条回答
  • 2020-12-23 14:29

    We can work it out by adding:

    import { TouchableOpacity } from 'react-native';
        <TouchableOpacity onPress={()=>this.setState({modalVisibilty:false})}>
        <View style={{opacity:0, flex:1 }}/>
        </TouchableOpacity>
    

    under the window and another one above and change the layout style to fit your screen.

    Explanation:

    You will make 2 big hidden buttons to catch the user touch and change the modal visibility state to false.

    0 讨论(0)
  • 2020-12-23 14:31
    <Modal isVisible={this.state.isVisible}
    onBackdropPress={() => this.setState({ isVisible: false })}>
    <View style={{ flex: 1 }}>
    <Text>I am the modal content!</Text>
    </View>
    </Modal>
    
    0 讨论(0)
  • 2020-12-23 14:32

    Here is my perfectly working solution

    MODAL CODE:

    const ListInModal = ({ showListModal, onClose, data, onSelectItem }) => {
      return (
        <Modal animationType="none" transparent={true} visible={showListModal} onRequestClose={() => onClose(false)}>
          <TouchableOpacity onPress={() => onClose(false)} style={styles.centeredView}>
            <View style={styles.modalView}>
              <ScrollView showsVerticalScrollIndicator={false}>
                {data.map((item, index) => (
                  <>
                    <TouchableOpacity
                      onPress={() => {
                        onSelectItem(item);
                        onClose(false);
                      }}
                      style={{ height: 43, justifyContent: 'center' }}
                    >
                      <Text style={styles.itemLabel}>{item.label}</Text>
                    </TouchableOpacity>
                    {index <= data.length - 2 && (
                      <View
                        style={{
                          borderBottomColor: colors.white,
                          opacity: 0.2,
                          borderWidth: 1,
                          marginHorizontal: (24 / 375) * screenWidth,
                        }}
                      />
                    )}
                  </>
                ))}
              </ScrollView>
            </View>
          </TouchableOpacity>
        </Modal>
      );
    };
    

    STYLING:

    const styles = StyleSheet.create({
      centeredView: {
        flex: 1,
        justifyContent: 'center',
        backgroundColor: '#00000099',
      },
      modalView: {
        marginHorizontal: wp('5%'),
        marginVertical: hp('10%'),
        backgroundColor: colors.popupBlack,
        borderRadius: 20,
        shadowColor: '#000',
        shadowOffset: {
          width: 0,
          height: 2,
        },
        shadowOpacity: 0.25,
        shadowRadius: 3.84,
        elevation: 5,
      },
      itemLabel: {
        fontSize: wp('5%'),
        color: colors.white,
        paddingHorizontal: (24 / 375) * screenWidth,
      },
    });
    

    USAGE:

    <ListInModal
      data={projectState?.lvApplicationTypeList}
      showListModal={showListModal}
      onClose={(bool) => setshowListModal(bool)}
      onSelectItem={(item) => onPressApplicationType(item.label)}
    />
    
    0 讨论(0)
  • 2020-12-23 14:36

    Simple solution. You need one touchableOpacity for clicking outside and another touchableOpacity for actual modal that will do nothing onPress.

    import React, { Component } from 'react'
    import { View, StyleSheet, TouchableOpacity, Modal} from 'react-native';
    
    export class Modal extends Component {
        constructor(props){
            this.state = { modalVisible : true}
        }
        render() {
            return (
                <View>
                    <Modal
                        animationType="slide"
                        transparent={true}
                        visible={this.state.modalVisible}
                        onRequestClose={() => { this.setState({modalVisible: false})
                        }}
                      >
                        <TouchableOpacity style={styles.modalContainer} onPress={() => { this.setState({ modalVisible : false})}}>
                            <TouchableOpacity style={styles.modal} onPress={() => console.log('do nothing')} activeOpacity={1} >
                                Modal Content...
                            </TouchableOpacity>
                        </TouchableOpacity>
                    </Modal>
                </View>
            )
        }
    }
    
    
    const styles = StyleSheet.create({
        modalContainer: {
          flex: 1,
          justifyContent: 'center',
          alignItems: 'center',
        },
        modal: {
          width: 155,
          height: 300
        },
    });
    
    export default Modal;
    

    activeOpacity={1} just removes touchableOpacity fade effect

    0 讨论(0)
  • 2020-12-23 14:37

    If I understood correctly, you want to close the modal when the user clicks outside of it, right ?

    If yes, I searched for this some time ago and the only solution that I remember was this one (which is the one that I've been using so far):

    render() { 
      if (!this.state.modalVisible)
        return null
      return (
         <View>
            <Modal 
              animationType="fade"
              transparent={true}
              visible={this.state.modalVisible}
              onRequestClose={() => {this.setModalVisible(false)}}
            >
              <TouchableOpacity 
                style={styles.container} 
                activeOpacity={1} 
                onPressOut={() => {this.setModalVisible(false)}}
              >
                <ScrollView 
                  directionalLockEnabled={true} 
                  contentContainerStyle={styles.scrollModal}
                >
                  <TouchableWithoutFeedback>
                    <View style={styles.modalContainer}>
                      // Here you put the content of your modal.
                    </View>
                  </TouchableWithoutFeedback>
                </ScrollView>
              </TouchableOpacity>   
            </Modal> 
         </View>
      )
    } 
    
    // Then on setModalVisible(), you do everything that you need to do when closing or opening the modal.
    setModalVisible(visible) {
        this.setState({
            modalVisible: visible,
        })
    }
    

    Explanation

    This is basically using a TouchableOpacity in the whole screen to get when the user clicks to close the modal. The TouchableWithoutFeedback is to avoid the TouchableOpacity to work inside of the Modal.

    If you have a better solution, please share here.

    0 讨论(0)
  • 2020-12-23 14:38

    Simple solution with simple code, if you are using expo.
    Here is a complete component which can you just copy and paste and get it working.

    //MyModal.js
    
    import React from 'react';
    import { BlurView } from 'expo-blur';
    import { View, StyleSheet, Modal, TouchableWithoutFeedback } from 'react-native';
    
    export const MyModal = ({ children, visible, onRequestClose, onPressOverlay, }) => {
      return (
         <Modal
          visible={visible}
          transparent
          animationType='none'
          onRequestClose={onRequestClose}
         >
           <TouchableWithoutFeedback onPress={onPressOverlay}>
             <BlurView
               style={{ ...StyleSheet.absoluteFill }}
               tint='dark'
               intensity={100}
             />
           </TouchableWithoutFeedback>
           <View style={styles.container}>
             {children}
           </View>
        </Modal>
      );
    };
    
    const styles = StyleSheet.create({
      container: {
        height: '100%',
        width: '100%',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
      },
    });
    

    Now you can import it into your work-space and use it like this.
    I'm using functional component and useState hook to show or hide the modal.

    //yourScreen.js
    
    import React, { useState } from 'react';
    import { View, Button } from 'react-native';
    import { MyModal } form './path/to/MyModal.js';
    
    const YourScreen = () => {
      const [modalVisible, setModalVisible] = useState(false);
      return (
        <View style={{ flex:1 }}>
          <MyModal
            visible={modalVisible}
            onRequestClose={()=>{
              setModalVisible(false);
            }}
            onPressOverlay={()=>{
              setModalVisible(!modalVisible);
            }}
          >
            // your modal content goes here
          </MyModal>
          <Button
            title='Show Modal' 
            onPress={()=>{
              setModalVisible(!modalVisible);
            }}
          />
        </View>
      );
    }
    
    export default YourScreen;
    
    0 讨论(0)
提交回复
热议问题