模态框应用于界面弹窗,为用户提供通知、选择、浏览等功能的组件。在RN中,模态框通过Moadl标签引用。使用时注意,可以把Modal看成一个仅提供功能的外壳,它不包含任何样式,只负责显示/隐藏和动画效果实现。Modal的子组件通常为一个View容器,在该View容器实现渲染界面和样式相关。在很多APP应用模态框的时候,出于视觉的优化,Modal子组件最外层的View容器为一层占满全屏的半透明背景层。

Modal的属性:

属性描述

animationType

指定了 modal 的动画类型。类型:slide 从底部滑入滑出|fade 淡入淡出|none 没有动画

transparent

背景是否透明,默认为白色,当为true时表示背景为透明

visible

boolean值,是否显示 modal 窗口

onRequestClose

回调会在用户按下 Android 设备上的后退按键或是 Apple TV 上的菜单键时触发。请务必注意本属性在 Android 平台上为必填,且会在 modal 处于开启状态时阻止BackHandler事件

onShow

回调函数会在 modal 显示时调用

贴士代码:

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

class ModalComp extends React.Component{

    state = {
            modalVisible: false
    };
    
    _openModalWin = () => {
        this.setState({modalVisible: true});
    }

    _closeModalWin = () => {
        this.setState({modalVisible: false});
    }

    render(){
        return(
            <View style={styles.container}>
                <View style={styles.contentStyle}>
                    <Text style={styles.contentTextStyle}>
                        ModalComp
                    </Text>
                    <Button
                        title="打开Modal窗口"
                        color="#841584"
                        onPress={this._openModalWin}
                    />
                </View>

                <Modal
                    animationType='fade' // 指定了 modal 的动画类型。类型:slide 从底部滑入滑出|fade 淡入淡出|none 没有动画
                    transparent={true} // 背景是否透明,默认为白色,当为true时表示背景为透明。
                    visible={this.state.modalVisible} // 是否显示 modal 窗口
                    onRequestClose={() => { this._closeModalWin(); }} // 回调会在用户按下 Android 设备上的后退按键或是 Apple TV 上的菜单键时触发。请务必注意本属性在 Android 平台上为必填,且会在 modal 处于开启状态时阻止BackHandler事件
                    onShow={()=>{console.log('modal窗口显示了');}} // 回调函数会在 modal 显示时调用
                >
                    <View style={styles.modalLayer}>
                        <View style={styles.modalContainer}>
                            <Text style={styles.modalTitleStyle}>这是个Modal窗口!</Text>
                            <View style={styles.modalButtonStyle}>
                                <Button 
                                    title='取消' 
                                    color="#A4A4A4"
                                    onPress={this._closeModalWin}
                                ></Button>
                            </View>
                        </View>
                    </View>
                </Modal>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1
    },
    contentStyle: {
        padding:30
    },
    contentTextStyle: {
        textAlign: 'center',
        fontSize: 26
    },
    modalLayer: {
        backgroundColor: 'rgba(0, 0, 0, 0.45)',
        flex: 1,
        justifyContent: 'center',
        padding: 32
    },
    modalContainer: {
        height: 300,
        backgroundColor: 'white',
        justifyContent: 'center'
    },
    modalTitleStyle: {
        textAlign: 'center',
        fontSize: 26
    },
    modalButtonStyle: {
        paddingLeft: 30,
        paddingRight: 30,
        marginTop: 10
    }
});

export default ModalComp;

效果:

还有一种常见的模态框应用场景,就是从底部弹出一组可选菜单,这类组件叫做ActionSheet组件。

贴上代码:ActionSheet组件

import React, {Component} from 'react';
import {
    View,
    StyleSheet,
    Text,
    Modal,
    TouchableOpacity,
    Dimensions
} from 'react-native';
import PropTypes from 'prop-types';

const {width} = Dimensions.get('window');

class ActionSheetComp extends Component{
    // 入参类型
    static propTypes={
        items:PropTypes.array,
        modalTitle:PropTypes.string,
        visible: PropTypes.bool
    }

    // 默认值
    static defaultProps={
        items:[
            {
                title: '拍照',
                click: () => {
                    console.log('拍照');
                }
            },
            {
                title: '录像',
                click: () => {
                    console.log('录像');
                }
            }
        ],
        modalTitle:'你需要拍照或录像?',
        visible: false
    }

   state = {
        modalVisible: this.props.visible,
    };
    
    // 该钩子函数表示当父组件的props入参改变时调用,常用于父组件入参变化影响子组件渲染
    UNSAFE_componentWillReceiveProps(newProps){
        this.setState({modalVisible:newProps.visible});
    }
    
    cancelModal(){
        this.setState({modalVisible:false});
    }

    render(){
        let actionSheets = this.props.items.map((item,i)=>{
           return(
               <TouchableOpacity
                   key={i}
                   style={styles.actionItem}
                   onPress={item.click}>
                   <Text style={styles.actionItemTitle}>
                        {item.title}
                    </Text>
               </TouchableOpacity>
               );
        });

        return (
            <Modal 
                animationType="slide"
                visible={this.state.modalVisible}
                transparent={true}
                onRequestClose={()=>this.setState({modalVisible:false})}
            >
                <View style={styles.modalStyle}>
                    <View style={styles.subView}>
                        <View style={styles.itemContainer}>
                            <Text style={styles.actionTitle}>
                                {this.props.modalTitle}
                            </Text>
                            {actionSheets}
                        </View>
                        <View style={[styles.itemContainer]}>
                            <TouchableOpacity
                                style={[styles.actionItem, {borderTopWidth:0}]}
                                onPress={()=>this.setState({modalVisible:false})}>
                                <Text style={styles.actionItemTitle}>取消</Text>
                            </TouchableOpacity>
                        </View>
                    </View>
                </View>
            </Modal>
        );
    }
}
const styles = StyleSheet.create({
    modalStyle:{
        justifyContent:'flex-end',
        alignItems:'center',
        flex:1
    },
    subView:{
        justifyContent:'flex-end',
        alignItems:'center',
        alignSelf:'stretch',
        width:width,
    },
    itemContainer:{
        marginLeft:15,
        marginRight:15,
        marginBottom:15,
        borderRadius:6,
        backgroundColor:'#fff',
        justifyContent:'center',
        alignItems:'center',
    },
    actionItem:{
        width:width-30,
        height:45,
        alignItems:'center',
        justifyContent:'center',
        borderTopColor:'#cccccc',
        borderTopWidth:0.5,
    },
    actionTitle:{
        fontSize:13,
        color:'#808080',
        textAlign:'center',
        paddingTop:10,
        paddingBottom:10,
        paddingLeft:15,
        paddingRight:15,
    },
    actionItemTitle:{
        fontSize:16,
        color:'#444444',
        textAlign:'center',
    },
});
export default ActionSheetComp;

引用组件:

import React, { Component } from 'react';
import { View, Button } from 'react-native';
import ActionSheetComp from '../example/comp/ActionSheetComp';

class MainView extends Component {

    state = {
        visible: false
    }

    _showModal = () => {
        this.setState({visible:true});
    }

    render(){
        return (
            <View style={{flex:1, backgroundColor: '#E4E4E4'}}>
                <Button
                    title='显示'
                    onPress={this._showModal}
                />
                <ActionSheetComp visible={this.state.visible} />
            </View>
        );
    }
}

export default MainView;

效果:

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐