React Native Modal打开时如何设置深灰色暗化背景遮罩
React Native Modal 弹出时背景暗化遮罩实现方案
问题原因
你之前两种方案不生效的核心原因:
- 修改外层主视图背景色无效:React Native 的 Modal 是独立于页面根视图渲染的原生浮层,始终盖在普通页面视图最上方,修改下层视图的样式会被Modal层完全覆盖,无法呈现效果。
- 直接给Modal组件设置backgroundColor无效:当你给Modal设置
transparent={true}属性时,Modal自身的原生容器默认是全透明状态,组件本身不支持直接通过style属性设置背景,样式只会作用在内部的子视图上。
你当前代码的问题是:Modal开启透明模式后,直接挂载的第一个子视图是宽度仅90%、背景为白色的弹窗内容块,剩余区域没有任何渲染内容,因此完全透明露出下层页面,自然不会出现暗化遮罩。
正确实现方法
在Modal开启透明模式的前提下,将第一级子视图设置为撑满全屏的遮罩容器,给这个容器设置半透明深灰色背景,再把你的弹窗内容块作为遮罩容器的子元素放置即可。
具体修改(仅需调整SortBy.js文件)
- 调整Modal内部的视图层级,新增全屏遮罩层
- 给遮罩层添加对应样式,同时可以通过flex布局让弹窗内容自动居中
- (可选)给遮罩层添加点击关闭逻辑,注意阻止弹窗内容区域的事件冒泡,避免点击弹窗内容时误触发关闭
修改后的SortBy.js完整代码如下:
import React from "react"; import {View, Text, Modal, StyleSheet, Button, FlatList, TouchableWithoutFeedback} from "react-native"; import { RadioButton } from "react-native-paper"; export default class Sortby extends React.Component { constructor(props) { super(props); } state = { selectedIndex: 0, radioButtonValue: 'asc', }; onRadiochange = (index, value) => { this.setState({ radioButtonValue: value, selectedIndex: index }); }; render() { return ( <Modal visible={this.props.visible} transparent={true}> {/* 全屏遮罩层 */} <TouchableWithoutFeedback onPress={this.props.onCancel}> <View style={styles.maskContainer}> {/* 弹窗内容块,阻止点击事件冒泡到遮罩 */} <TouchableWithoutFeedback> <View style={styles.modalStyles}> <View style={styles.fieldsContainer}> <FlatList data={this.props.showInGridViewList()} extraData={this.state} renderItem={(itemData) => { const index = itemData.index; return ( <View style={styles.fieldItem}> <Text style={styles.fieldText}>{itemData.item.text}</Text> <View style={styles.radioButtonContainer}> <RadioButton.Group onValueChange={value => this.onRadiochange(index, value)}> <View style={styles.singleRadioButtonContainer}> <Text>Asc</Text> <RadioButton color='#5d86d7' value="asc" status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'asc' ? 'checked' : 'unchecked'} /> </View> <View style={styles.singleRadioButtonContainer}> <Text>Desc</Text> <RadioButton color='#5d86d7' value="desc" status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'desc' ? 'checked' : 'unchecked'} /> </View> </RadioButton.Group> </View> </View> ); }} alwaysBounceVertical={false} /> </View> <View style={styles.buttonContainer}> <View style={styles.button}> <Button title="OK" color="#5d86d7" onPress={this.props.onOK}></Button> </View> <View style={styles.button}> <Button title="Cancel" color="#5d86d7" onPress={this.props.onCancel} ></Button> </View> </View> </View> </TouchableWithoutFeedback> </View> </TouchableWithoutFeedback> </Modal> ); } } const styles = StyleSheet.create({ // 遮罩层样式 maskContainer: { flex: 1, backgroundColor: 'rgba(0,0,0,0.6)', // 0.6透明度黑色遮罩,可自行调整透明度和色值 justifyContent: 'center', alignItems: 'center', }, modalStyles: { width: "90%", flexDirection: "column", justifyContent: "flex-start", alignItems: "center", backgroundColor: "#fff", borderColor: "#777", borderWidth: 1, borderRadius: 8, overflow: 'hidden', }, fieldsContainer: { width: "100%", }, fieldItem: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingLeft: 12, paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: "#ebebeb", }, fieldText: { color: "#444", }, radioButtonContainer: { flexDirection: "row", justifyContent: "flex-start", alignItems: "center", }, singleRadioButtonContainer: { flexDirection: "row", justifyContent: "center", alignItems: "center", marginRight: 10, }, buttonContainer: { flexDirection: "row", justifyContent: "center", alignItems: "center", paddingVertical: 12, }, button: { flex: 1, marginHorizontal: 8, }, });
关键参数说明
- 遮罩层颜色
rgba(0,0,0,0.6):最后一位参数为透明度,取值范围0-1,数值越大遮罩颜色越深,可根据视觉需求自行调整。 - 嵌套
TouchableWithoutFeedback的作用:外层绑定关闭方法实现点击遮罩关闭弹窗,内层空绑定是为了阻止点击弹窗内容时事件冒泡到遮罩层,避免误触发关闭。 - 移除了原
modalStyles中冗余的height: "auto"和marginLeft: 20属性,父容器已设置居中布局,View默认自适应内容高度,不需要额外左边距避免弹窗偏移。
内容的提问来源于stack exchange,提问作者Steph
相关产品推荐
相关产品推荐

