React Native 模态框增强功能实现

在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重叠,因为它不在正常布局流中。如果想同时使用按钮旁边和下方的空间,这几乎是不可能的,这导致选择第二种选项。
  • 使用flexbox定位按钮,为按钮左侧留出空间用于标题。然后可以分别填充标题和底部的内容。如果正在做的事情意味着是一个弹出窗口,有一个标题也是一个相当标准的功能。

以下是现在带有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的背景色不能设置为透明或半透明值,因此弹出窗口下的内容将不再可见。

下一步是将模态框组件及其所有内容打包成一个新的组件,以便在应用程序中重复使用,以便在弹出窗口中插入任何标题或内容,但这超出了当前文章的范围。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485