通过点击覆盖关闭反应本机模式?

transparent选项为 true时,是否可以通过点击叠加来关闭 反应本机模态反应本机模态?文档没有提供任何相关信息。有可能吗?

121448 次浏览

如果我理解正确的话,您希望在用户单击模式外部时关闭模式,对吗?

如果答案是肯定的,我前段时间搜索过这个问题,我记得唯一的解决方案就是这个问题 我到目前为止一直在使用的) :

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,
})
}

解释

这基本上是在整个屏幕中使用 TouchableOpacity,以便在用户单击关闭模态时获得。触摸无反馈是为了避免触摸不透明的工作内部的模式。

如果你有更好的解决方案,请在这里分享。

我们可以加上:

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

改变布局样式以适合你的屏幕。

说明:

您将使2大隐藏按钮捕捉用户触摸和改变模态可见性状态为假。

另一个解决办法:

// 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;

用法例子:

// 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>
);
}
}

嗨,我正在使用一个轻量级弹出式 react-native-easypopup它也关闭自己,当你点击弹出式。

npm i react-native-easypopup

        <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>

这个代码就是我的解决方案。

<Modal isVisible={this.state.isVisible}
onBackdropPress={() => this.setState({ isVisible: false })}>
<View style=\{\{ flex: 1 }}>
<Text>I am the modal content!</Text>
</View>
</Modal>

下面是我的简单实现:

<TouchableWithoutFeedback onPress={}> // Code to close your modal goes here
<View style={styles.background}> // The view to drawn the background
<View
onStartShouldSetResponder={() => true}
style={styles.container}
> // The view to drawn your modal
// Your content
</View>
</Androw>
</View>
</TouchableWithoutFeedback>

我使用 TouchableWithout 反馈,因为我不想改变背景颜色时点击它。我还在模态视图上添加了 onStartShouldSetResponder,以防止在单击视图内部时关闭模态。

我也没有使用 Modal 组件,因为我使用的是反应导航。

简单的解决方案与简单的代码,如果您正在使用 expo
这里有一个完整的组件,你可以只是复制和粘贴,让它工作。

//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',
},
});

现在您可以将它导入到您的工作空间中,并像这样使用它。
我使用 功能组件功能组件useState钩显示或隐藏的 模态

//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;

如果你使用 储存解决方案mobxredux, 你可以简单地解决商店的旗帜。

下面是家长代码,

      <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>

下面是孩子的代码。(使用 mobx)

const YourCustomDialog: React.FC = observer(() => {
const { uiControlStore } = useStores();


return (
<View
style={[styles.container, styles.border]}
onTouchStart={() => {
uiControlStore.childClicked= true;
}}
>
...
)
}


这是我的解决办法,

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,
},
});

我知道我来晚了。但我无意中发现了这个线索桂 · 赫尔佐格的回答正是我想要的。如果您不想添加任何外部依赖项,那么这就是解决方法。谢谢!

然而,我想包括一些可选的消极/积极行动按钮在我的组成部分,并抓住他们从反应-本地纸的材质风格。 那时我才意识到——本土纸张可能也有模态。

这是他们的文件: Https://callstack.github.io/react-native-paper/modal.html
它们还有一个 Dialogs 组件 Https://callstack.github.io/react-native-paper/dialog.html

所以我最终使用了纸质对话框,如果你打算在整个应用程序中使用这个库的话,它是非常值得的。默认情况下,Dialog 和 Modal 都可以在单击外部时处理解雇。


下面是在实现 Dialog 组件之前创建的一个 Dialog 组件。

无论如何,我将把我实现的内容留在这里,因为我认为它是一个很好的模板。

组件是用打字机打出来的。请确保更新了 @types/react-native,否则您可能会看到一些“没有重载匹配此调用”错误。

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,
},
});

简单的解决方案。您需要一个外部点击触摸不透明度和另一个触摸不透明度的实际模式,将不会做任何新闻。

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}只是移除了可触摸的不透明淡出效果

这是我完美的解决方案

模式代码:

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>
);
};

造型:

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,
},
});

用法:

<ListInModal
data={projectState?.lvApplicationTypeList}
showListModal={showListModal}
onClose={(bool) => setshowListModal(bool)}
onSelectItem={(item) => onPressApplicationType(item.label)}
/>

通过下面的代码,我已经在本机0.64中解决了这个问题

 <Modal
isVisible={ModalVisible}


onBackdropPress={()=>{setModalVisible(false)}}
>
.
.
.
</Modal>

这是我做的。

<Modal
visible={isVisible}
onRequestClose={() => setIsVisible(false)}
transparent={true}
      

>
<Pressable style=\{\{
flex:1,
backgroundColor:'transparent',
            

}}
onPress={()=>setIsVisible(false)}
/>
{/* Here comes your component*/}
</Modal>

position:absoute制作你的组件,这样 Pressable就可以覆盖整个背景。

这是一个基于钩子的模态系统。

Https://www.npmjs.com/package/@idiosync/react-native-modal

您可以向 config 对象添加一个 onBackoundPress 函数,以实现您想要的效果:

useModal(
{
// all config params are optional apart from renderModal
renderModal: () => <MyModal onClose={() => setModalIsVisible(false)} someProp={someProp} />,
onBackgroundPress: () => setModalIsVisible(false),
animationTypeIn: AnimationType.SLIDE_TOP,
},
modalIsVisible,
[someProp] // dependencies array to trigger rerenders. Empty array is passed by default
)

这里有一个最好的解决方案,你只需要复制粘贴就可以了。

我也面临问题,这是解决办法。

import React,{useState} from 'react';


import{Button,StyleSheet,View,TouchableOpacity,Modal} from 'react-native';


const App=()=>{
const [show, setShow] = useState(false);
return (
<View>
<TouchableOpacity style=\{\{marginTop:200}}>
<Button title='show' onPress={()=>setShow(!show)}/>
</TouchableOpacity>
<Modal transparent={true} visible={show} animationType="slide">
<TouchableOpacity activeOpacity={1} style=\{\{backgroundColor:'#000000aa',flex:1}} onPress={()=>setShow(!show)}/>
            

<View style=\{\{backgroundColor:'#FFFFFF',flex: 1}}>
<View >
<Button title='close' onPress={()=>setShow(!show)}/>
</View>
</View>
</Modal>
</View>
)};
export default App;

你可以在这里查看另一个例子:
Https://snack.expo.dev/@saurabh_chavan/model-with-border-radius

我试图实现一些建议的答案,但没有工作与按钮内的模态。

我在谷歌上搜索了一下,发现与使用 TouchableWithoutFeedback不同的是,名为 Pressable的本地组件允许您检查您点击的内容,因此只允许您在点击时关闭它,而不是关闭它的子组件。

return (
<View>
<Modal
animationType="slide"
transparent={true}
visible={visible}
onRequestClose={() => {
setVisible(false)}}
>
<Pressable
onPress={(event) => event.target == event.currentTarget && setVisible(false)}
style={styles.background}
>
<View style={styles.modal}>
//Content of the modal
</View>
</Pressable>
</Modal>
</View>
)

找到答案了。

2022答案-使用反应本机钩

通过点击一个覆盖来关闭一个反应本机模式最好使用一个按钮和 TouchableOpacity

下面的例子..。

  • 从本地反应导入 Pressable 和其他
import React, { useState } from 'react';
import {
Pressable,
View,
Text,
TouchableOpacity,
ScrollView,
Modal,
TextInput,
StyleSheet,
} from 'react-native';
  • 然后设置一个状态
const [modalVisible, setModalVisible] = useState(false);
  • 然后编写和设计你的模式
        <Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<TouchableOpacity
onPress={() => setModalVisible(false)}
style={styles.modalContainerStyle}
>
<Pressable
onPress={() => setModalVisible(true)}
style={styles.modalContent}
>
<ScrollView>
<View>
<Text style={styles.modalTitle}>TITLE HERE</Text>


<Text style={styles.modalText}>
OTHER SMALLER TEXT HERE
</Text>


<Text style={styles.modalFormText}>AN INPUT</Text>
<TextInput
style={styles.modalInput}
value={inputValue}
onChangeText={(inputValue) => handleInputValue(inputValue)}
placeholder={'example@email.com'}
/>


<View style={styles.btnView}>
<TouchableOpacity
onPress={() => setModalVisible(!modalVisible)}
underlayColor="white"
>
<View style={styles.buttonProceed}>
<Text style={styles.buttonText}>NEXT</Text>
</View>
</TouchableOpacity>
</View>
</View>
</ScrollView>
</Pressable>
</TouchableOpacity>
</Modal>


  • 现在打开您的模式(使用文本按钮)
<Pressable onPress={() => setModalVisible(!modalVisible)}>
<Text style={styles.openModal}>Open Modal</Text>
</Pressable>
  • 最终风格你的模态
modalContainerStyle: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'flex-end',
backgroundColor: 'rgba(0, 0, 0, 0.3)',
},
modalContent: {
borderTopLeftRadius: 27,
borderTopRightRadius: 27,
width: '100%',
height: '60%',
backgroundColor: '#FFFFFF',
paddingLeft: 33,
paddingRight: 33,
overflow: 'hidden',
},
modalTitle: {
marginTop: 43,
marginBottom: 14,
fontSize: 19,
lineHeight: 21,
color: 'black',
fontFamily: 'GraphikBold',
},
modalText: {
fontSize: 15,
lineHeight: 25,
marginBottom: 38,
color: 'black',
fontFamily: 'GraphikRegular',
},
modalFormText: {
marginBottom: 10,
fontSize: 15,
color: 'black',
fontFamily: 'GraphikMedium',
},
modalInput: {
marginBottom: 99,
height: 44,
paddingLeft: 17,
paddingRight: 17,
fontSize: 16,
borderRadius: 10,
marginBottom: 20,
borderWidth: 1,
fontFamily: 'GraphikRegular',
borderColor: 'rgba(118, 118, 118, 0.17)',
},
openModal: {
marginRight: 5,
textAlign: 'right',
color: '#ED2125',
fontFamily: 'GraphikMedium',
},

最近面临的问题,试图解决它使用两个可触摸的不透明度, 您还可以通过将 isDismisable 值传递给 false 来关闭在任何位置点击行为的关闭。

import { View, Text, Modal, StyleSheet, TouchableOpacity } from 'react-native';
import React from 'react';


type PropType = {
open: boolean;
onClose: () => void;
isDismissable?: boolean;
children: JSX.Element | JSX.Element[];
};


const styles = StyleSheet.create({
modalRootContainer: {
flexGrow: 1,
},
outerContainer: {
height: '100%',
},
});


const BottomModal = ({
open,
onClose,
isDismissable = true,
children,
}: PropType) => {
return (
<Modal
visible={open}
transparent
onRequestClose={onClose}
animationType='slide'
>
<TouchableOpacity
style={styles.outerContainer}
activeOpacity={1}
onPress={() => {
if (isDismissable) onClose();
}}
>
<View style={styles.modalRootContainer}>
<TouchableOpacity activeOpacity={1}>{children}</TouchableOpacity>
</View>
</TouchableOpacity>
</Modal>
);
};


export default BottomModal;

使用 TouchableWithout 反馈和本地反应模式最好和最简单的方法是

<Modal
visible={visible}//modal visible true or false
onRequestClose={()=>onClose(false)} // function to close modal
transparent={true}
>
<TouchableWithoutFeedback
onPress={()=>onClose(false)}//outer button/view
<View style=\{\{flex:1, backgroundColor:'rgba(0,0,0,0.5)'}}>//for transparent view, this is outer view
<TouchableWithoutFeedback>// outer button so any child view can be added
<View>// this inner view
<View>
//your content goes here
</View>
</View>
</TouchableWithoutFeedback>
</View>
</TouchableWithoutFeedback>
</Modal>

如果你想添加平面列表更好地提供高度,使内容不会走出视线

这是一个非常简单有效的解决方案,我只是将它应用到我的应用程序中,并按照我的意愿运行。 只需将子组件包装到 TouchableOpacity

例子:

 <Modal
animationType="slide"
transparent={true}
visible={IsCamaraShow}
onRequestClose={() => {
setIsCamaraShow(!IsCamaraShow);
}}>
<View style={Styles.centeredView1}>
<TouchableOpacity style={Styles.centeredView1}
onPress={()=> setIsCamaraShow(!IsCamaraShow)}
activeOpacity={1}
>
<View style={Styles.modalView1}>
           

{cosnole.log( 'rest of your code') }
  

</View>
</TouchableOpacity>
</View>
</Modal>