react-native系列(10)組件篇:Modal模態框實現彈窗效果

模態框應用於界面彈窗,爲用戶提供通知、選擇、瀏覽等功能的組件。在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;

效果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章