Close react native modal by clicking on overlay?

前端 未结 13 655
梦如初夏
梦如初夏 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:40
            <Modal
                animationType="slide"
                closeOnClick={true}
                transparent={true}
                visible={this.state.modalVisible}
                >
                <TouchableOpacity onPress={() => { this.setModalVisible(!this.state.modalVisible)}} style={{flex:1, justifyContent:'center', alignItems:'center',}}>
                    <View style={{flex:0.2,backgroundColor:'white', margin:20, borderRadius:20, borderWidth:2, borderColor:'gray'}}>
                        <Text style={{margin:20}}>모달 테스트</Text>
                    </View>
                </TouchableOpacity>
            </Modal>
    

    this code is my solution.

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

    Here is my solution,

    import React from "react";
    import {Modal, StyleSheet, TouchableOpacity, TouchableWithoutFeedback, View} from "react-native";
    
    // make sure the styles props is passed to the model and contains modalContainer, as well as the childrenContainer style objects.
    
    export default class DismissibleModal extends React.Component {
        render() {
            return (
                <Modal
                  animationType="slide"
                  transparent={true}
                  visible={this.props.visible}
                  onRequestClose={() => {this.props.dismiss()}}>
                  <TouchableOpacity
                    style={Styles.modal}
                    activeOpacity={1}
                    onPressOut={() => {this.props.dismiss()}}>
                        <View style={[this.props.styles.modalContainer]}>
                            <TouchableWithoutFeedback>
                                <View style={[this.props.styles.childrenContainer]}>
                                    {this.props.children}
                                </View>
                            </TouchableWithoutFeedback>
                        </View>
                  </TouchableOpacity>
            </Modal>
            )
        }
    
    }
    
    
    
    const Styles = StyleSheet.create({
        modal: {
            flex: 1,
            backgroundColor: 'transparent',
            flexDirection: 'row',
            justifyContent: 'center',
            alignItems: 'center'
        },
        modalView: {
            backgroundColor: "white",
            borderRadius: 10,
            padding: 20,
            paddingTop: 20,
            alignItems: "center",
            shadowColor: "#000",
            shadowOffset: {
                width: 0,
                height: 9,
            },
            shadowOpacity: 0.50,
            shadowRadius: 12.35,
    
            elevation: 19,
      },
    });
    
    0 讨论(0)
  • 2020-12-23 14:43

    I realize I'm very late to this party. But I just stumbled upon this thread and Gui Herzog's answer was exactly what I was looking for. If you don't want to add any outside dependencies that is the way to go. Thanks!

    However, I wanted to include some optional negative/positive action buttons in my component and grabbed them from react-native-paper for the material style. That's when I realized react-native-paper probably have modals as well.

    Here's their documentation: https://callstack.github.io/react-native-paper/modal.html
    They also have a component for Dialogs https://callstack.github.io/react-native-paper/dialog.html

    So I ended up with using the paper Dialog and it's well worth if if you're going to use the library throughout you app. Both Dialog and Modal handles the dismiss on click outside by default.


    Here's a Dialog component created before realizing the Dialog component already exists.

    I'll leave what I implemented here anyways as I think its a good template.

    The component is in typescript. Make sure to have @types/react-native updated otherwise you might see some "No overload matches this call" errors.

    import React from 'react';
    import {View, Text, StyleSheet} from 'react-native';
    import {Button, Modal, Portal} from 'react-native-paper';
    
    interface Action {
      action: () => void;
      text: string;
    }
    
    interface Props {
      closePressed: () => void;
      negativeAction?: Action;
      positiveAction?: Action;
      title?: string;
      text: string;
      visible: boolean;
    }
    
    export const Dialog: React.FC<Props> = ({
      closePressed,
      negativeAction,
      positiveAction,
      title,
      text,
      visible,
    }) => {
      return (
        <Portal>
          <Modal
            visible={visible}
            onDismiss={closePressed}
            contentContainerStyle={styles.modalContainer}>
            <View style={styles.header}>
              {title && (
                <Text style={{fontWeight: 'bold', fontSize: 18, marginBottom: 10}}>
                  {title}
                </Text>
              )}
              <Text style={styles.contentText}>{text}</Text>
            </View>
            <View style={styles.buttonContainer}>
              {negativeAction && (
                <Button mode="text" onPress={negativeAction.action}>
                  {negativeAction.text}
                </Button>
              )}
              {positiveAction && (
                <Button mode="text" onPress={positiveAction.action}>
                  {positiveAction.text}
                </Button>
              )}
            </View>
          </Modal>
        </Portal>
      );
    };
    
    const styles = StyleSheet.create({
      modalContainer: {
        borderRadius: 5,
        backgroundColor: 'white',
        padding: 10,
        margin: 20,
      },
      header: {padding: 20},
      contentText: {color: 'grey'},
      buttonContainer: {
        flexDirection: 'row',
        justifyContent: 'flex-end',
        paddingTop: 20,
      },
    });
    
    0 讨论(0)
  • 2020-12-23 14:47

    If you are using store solution like mobx or redux, you can simply solve with the flag on store.

    Below is the parent's code,

          <Modal
            animationType="fade"
            transparent={true}
            visible={uiControlStore.dialogVisible}
            onRequestClose={() => {
              uiControlStore.dialogVisible = false;
            }}
          >
            <View
              style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(0,0,0,0.6)' }}
              onTouchStart={() => {
                if (!uiControlStore.childClicked) uiControlStore.dialogVisible = false;
                uiControlStore.childClicked= false;
              }}
            >
              <YourCustomDialog />
            </View>
          </Modal>
    

    and below is child's code. (using mobx)

    const YourCustomDialog: React.FC = observer(() => {
      const { uiControlStore } = useStores();
    
      return (
        <View
          style={[styles.container, styles.border]}
          onTouchStart={() => {
            uiControlStore.childClicked= true;
          }}
        >
        ...
      )
    }
    
    
    0 讨论(0)
  • 2020-12-23 14:49

    Hi I am using a lightweight popup react-native-easypopup it also closing itself when you tap out of popup.

    npm i react-native-easypopup

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

    Another solution:

    // Modal.js
    import React from 'react';
    import {
      TouchableWithoutFeedback,
      StyleSheet,
      Modal,
      View,
    } from 'react-native';
    import t from 'prop-types';
    
    
    class MyModal extends React.Component {
      static propTypes = {
        children: t.node.isRequired,
        visible: t.bool.isRequired,
        dismiss: t.func.isRequired,
        transparent: t.bool,
        animationType: t.string,
      };
    
      static defaultProps = {
        animationType: 'none',
        transparent: true,
      };
    
      render() {
        const { props } = this;
        return (
          <View>
            <Modal
              visible={props.visible}
              transparent={props.transparent}
              onRequestClose={props.dismiss}
              animationType={props.animationType}
            >
            <TouchableWithoutFeedback onPress={props.dismiss}>
              <View style={styles.modalOverlay} />
            </TouchableWithoutFeedback>
    
            <View style={styles.modalContent}>
              {props.children}
            </View>
            </Modal>
          </View>
        );
      }
    }
    
    
    const styles = StyleSheet.create({
      modalContent: {
        flex: 1,
        justifyContent: 'center',
        margin: '5%',
      },
      modalOverlay: {
        position: 'absolute',
        top: 0,
        bottom: 0,
        left: 0,
        right: 0,
        backgroundColor: 'rgba(0,0,0,0.5)'
      },
    });
    
    
    export default MyModal;
    

    Usage example:

    // SomeScreen.js
    import React from 'react';
    import { View, Text, Button } from 'react-native';
    
    import Modal from './Modal';
    
    
    class SomeScreen extends React.Component {
      state = {
        isModalVisible: false,
      };
    
      showModal = () => this.setState({ isModalVisible: true });
      hideModal = () => this.setState({ isModalVisible: false });
    
      render() {
        return (
          <View>
            <Button onPress={this.showModal} />
            <Modal
              visible={this.state.isModalVisible}
              dismiss={this.hideModal}
            >
              <Text>Hello, I am modal</Text>
            </Modal>
          </View>
        );
      }
    }
    
    0 讨论(0)
提交回复
热议问题