在React Native中,模态框(Modal)是一个基本的组件,用于在另一个视图之上显示视图。虽然它本身不包含关闭按钮或点击外部关闭等高级功能,但通过一些简单的步骤,可以为模态框添加这些功能。
首先,从基本的App.js文件开始,展示一个弹出窗口。为了使弹出窗口更加明显,添加了一些样式,包括阴影和足够的边距,以便稍后测试点击弹出窗口外部关闭它。
import React, { useState } from 'react';
import { StyleSheet, Modal, Text, View } from 'react-native';
export default function App() {
const [modalVisible, setModalVisible] = useState(true);
return (
打开App.js开始开发应用!
弹出窗口内容。
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
},
modal: {
flex: 1,
margin: 50,
padding: 5,
backgroundColor: 'white',
shadowColor: 'black',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
},
});
模态框根据其visible属性显示。目前状态中的值始终为true,因此弹出窗口将始终可见。即使没有按钮或其他方式来改变状态,模态框也可以通过Android上的后退按钮关闭(根据文档,Apple TV上的菜单按钮应该也有相同的效果,但没有设备进行测试)。
按下按钮会调用模态框的onRequestClose属性中指定的函数,因此让改变状态,当按下时隐藏弹出窗口,这将显示应用程序的主屏幕:
<Modal visible={modalVisible} onRequestClose={() => setModalVisible(false)}>
接下来,将添加一个按钮以便关闭弹出窗口。在这种情况下,想在弹出窗口的右上角添加一个小X,但它也可以在其他地方。
考虑到定位的工作方式,有两种选择:
以下是现在带有X的组件的样子:
import React, { useState } from 'react';
import { StyleSheet, Modal, Text, View, TouchableOpacity } from 'react-native';
export default function App() {
const [modalVisible, setModalVisible] = useState(true);
return (
打开App.js开始开发应用!
setModalVisible(false)}>
其他标题内容
setModalVisible(false)}>
X
弹出窗口内容。
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
},
modal: {
flex: 1,
margin: 50,
padding: 5,
backgroundColor: 'white',
shadowColor: 'black',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
},
modalContent: {
flex: 1,
},
modalHeader: {
flexDirection: 'row',
},
modalHeaderContent: {
flexGrow: 1,
},
modalHeaderCloseText: {
textAlign: 'center',
paddingLeft: 5,
paddingRight: 5,
},
});
标题是一个flex容器,显示为一行,具有flexGrow:1,表示它应该占据所有剩余空间。弹出窗口中的其余内容是一个flex:1项目,因此它占据了所有剩余的高度。
到目前为止,唯一剩下的就是将按钮连接起来,以便它关闭弹出窗口,就像之前在onRequestClose事件中设置的那样:
<TouchableOpacity onPress={() => setModalVisible(false)}>
<Text style={styles.modalHeaderCloseText}>X</Text>
</TouchableOpacity>
要通过点击外部关闭模态框,需要一个额外的组件来捕获这些点击。另一方面,不希望这个组件捕获子组件的点击:点击弹出窗口本身不应该关闭它。通过检查event.target == event.currentTarget,验证所选项目是组件本身,而不是其子项之一。
使用了Pressable组件,因为不想在触摸弹出窗口外部时出现“变暗”效果,这与TouchableOpacity一起使用。这个新的Pressable组件包裹了之前在模态框中定义的所有组件。
以下是完成的弹出窗口,还有一些额外的边框,显示了标题和弹出窗口内容的位置:
import React, { useState } from 'react';
import { StyleSheet, Modal, Text, View, Pressable, TouchableOpacity } from 'react-native';
export default function App() {
const [modalVisible, setModalVisible] = useState(true);
return (
打开App.js开始开发应用!
setModalVisible(false)}>
{
if (event.target == event.currentTarget) {
setModalVisible(false);
}
}}>
其他标题内容
setModalVisible(false)}>
X
弹出窗口内容。
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
},
modal: {
flex: 1,
margin: 50,
padding: 5,
backgroundColor: 'white',
shadowColor: 'black',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
},
modalContent: {
flex: 1,
borderWidth: 1,
borderColor: 'black',
},
modalHeader: {
flexDirection: 'row',
borderWidth: 1,
borderColor: 'black',
},
modalHeaderContent: {
flexGrow: 1,
},
modalHeaderCloseText: {
textAlign: 'center',
paddingLeft: 5,
paddingRight: 5,
},
outsideModal: {
backgroundColor: 'rgba(1, 1, 1, 0.2)',
flex: 1,
},
});
请注意,这里有一个限制:Pressable或TouchableOpacity的背景色不能设置为透明或半透明值,因此弹出窗口下的内容将不再可见。
下一步是将模态框组件及其所有内容打包成一个新的组件,以便在应用程序中重复使用,以便在弹出窗口中插入任何标题或内容,但这超出了当前文章的范围。