美文网首页
react native实现model效果/底部弹出框/中间弹框

react native实现model效果/底部弹出框/中间弹框

作者: cukiy | 来源:发表于2019-12-25 18:12 被阅读0次

    近期项目中用到一些弹框界面,经过几次优化后觉得挺好用,所以分享给大家。

    效果

    弹框.gif

    思路

    实现方法很简单,就做几个动画,没什么可说的。可以根据自己需求做一些调整。

    导入组件

    1. 新建一个js文件,将代码复制过去。我是放在coverLayer文件中。
    2. 导入该组件
    import CoverLayer from '../../../widgets/coverLayer';
    
    1. 在需要弹框的界面外层添加该组件并添加ref引用(具体位置根据情况而定,防止遮挡)
    render() {
        return(
            <View>
    
                   ......
    
                  {/* 在合适位置添加组件 */}
                  <CoverLayer ref={ref => this.coverLayer = ref}/>
            </view>
        )
    }
    
    

    使用组件

    该组件对外提供3个可自定义的属性

    coverLayerColor: PropTypes.string, //弹框背景颜色
    coverLayerEvent: PropTypes.func, // 点击背景后的回调
    renderContent: PropTypes.func // 渲染弹框内容的方法
    

    提供2个控制显示方法和一个控制隐藏方法

    /*** 显示弹框
       *    displayMode: 弹出方式(从底部/从中间弹出)
       */
    show(displayMode);
    
    /*** 显示弹框
       * renderContent: 内容渲染方法
       * coverLayerEvent: 点击背景的回调方法
       * displayMode: 弹出方式(从底部/从中间弹出)
       */
    showWithOptions(renderContent,coverLayerEvent,displayMode);
    
    /*** 隐藏弹框 ***/
    hide();
      
    

    使用方法有两种,建议使用第二种方法

    方法一:在组件中添加属性,然后在合适的地方调用组件的show和hide方法控制显示和隐藏。在一个界面多个弹框的情况下需要在renderContent方法中判断显示哪一个弹框,复杂度增加,所以建议使用第二种方法。

    <CoverLayer ref={ref => this.coverLayer = ref}
                renderContent={()=>{return <View></View>}}
                coverLayerEvent={()=>console.log("点击了背景")}
                coverLayerColor="rgba(0,0,0,0.2)"
    />
    
    // 显示
    showCoverLayer() {
        this.coverLayer.show();
    }
    
    // 隐藏
    hideCoverLayer() {
        this.coverLayer.hide();
    }
    

    方法二:调用组件提供的showWithContent方法。调用该方法后会自动显示弹框,只需要在合适的位置调用hide隐藏方法

    showPopupView() {
        // 根据传入的方法渲染并弹出
        this.coverLayer.showWithContent(
                    ()=> {
                        return (
                            <View style={{height:100,width:100,backgroundColor:"red"}}>
                            </View>
                        )
                    },
                ()=>this.coverLayer.hide(),
                CoverLayer.popupMode.bottom
            )
        }
    
     /*** 组件提供了一个类似枚举的弹出方式选项popupMode,
        * 可以直接使用导入的组件名.popupMode.center或组件名.popupMode.bottom控制弹出方式。
        * 当然直接传指定字符串也可以
        */
    
    // 隐藏
    hideCoverLayer() {
        this.coverLayer.hide();
    }
    

    附上完整代码

    import React, { Component , PropTypes } from 'react';
    
    import {
        TouchableOpacity,
        View,
        Animated,
        Dimensions
    } from 'react-native';
    
    const c_duration = 200;
    const c_deviceHeight = Dimensions.get("window").height;
    export default class CoverLayer extends Component {
    
        static propTypes = {
            coverLayerColor:PropTypes.string,
            coverLayerEvent:PropTypes.func,
            renderContent:PropTypes.func
        };
    
        static popupMode = {
            center:"center",
            bottom:"bottom"
        };
    
        // 构造
        constructor(props) {
            super(props);
            // 初始状态
            this.state = {
                isShow:false,
                opacityValue:new Animated.Value(0),
                scaleValue:new Animated.Value(1.1),
                bottom:new Animated.Value(-c_deviceHeight),
                renderContent:this.props.renderContent,
                coverLayerEvent:this.props.coverLayerEvent,
                displayMode:null
            };
            this.showAnimated = null;
            this.hideAnimated = null;
        }
    
        /**
         * 显示弹框(该方法是为了简化一个界面有多个弹框的情况)
         * renderContent: func, 渲染弹框内容的方法, 会覆盖this.props.renderContent
         * coverLayerEvent: func, 点击背景触发的事件, 会覆盖this.props.coverLayerEvent
         **/
        async showWithContent(renderContent,coverLayerEvent,displayMode) {
    
            if (this.state.isShow) {
                this.hide(async ()=>{
                    await this.setState({
                        coverLayerEvent:coverLayerEvent,
                        renderContent:renderContent
                    });
    
                    this.show(displayMode);
                })
            } else {
                await this.setState({
                    coverLayerEvent:coverLayerEvent,
                    renderContent:renderContent
                });
    
                this.show(displayMode);
            }
        }
    
        // 显示弹框
        show(displayMode) {
            this.setState({
                displayMode:displayMode,
                isShow:true
            });
    
            if (CoverLayer.popupMode.bottom == displayMode) {
                this.showAnimated = this.showFromBottom;
                this.hideAnimated = this.hideFromBottom;
            } else {
                this.showAnimated = this.showFromCenter;
                this.hideAnimated = this.hideFromCenter;
            }
    
            Animated.parallel([
                Animated.timing(this.state.opacityValue, {
                    toValue: 1,
                    duration: c_duration
                }),
                this.showAnimated()
            ]).start();
        }
    
    
        // 从中间弹出界面
        showFromCenter() {
            return (
                Animated.timing(this.state.scaleValue, {
                    toValue: 1,
                    duration: c_duration
                })
            )
        }
    
    
        // 从底部弹出界面
        showFromBottom() {
            return (
                Animated.timing(this.state.bottom, {
                    toValue: 0,
                    duration: c_duration
                })
            )
        }
    
    
        // 隐藏弹框
        hide(callback) {
            Animated.parallel([
                Animated.timing(this.state.opacityValue, {
                    toValue: 0,
                    duration: c_duration
                }),
                this.hideAnimated()
            ]).start(async ()=> {
                await this.setState({isShow: false});
                callback && callback();
            });
        }
    
        //从中间隐藏
        hideFromCenter() {
            return (
                Animated.timing(this.state.scaleValue, {
                    toValue: 1.1,
                    duration: c_duration
                })
            )
        }
    
        // 从底部隐藏
        hideFromBottom() {
            return (
                Animated.timing(this.state.bottom, {
                    toValue: -c_deviceHeight,
                    duration: c_duration
                })
            )
        }
    
        render() {
            return(
                this.state.isShow &&
                <Animated.View style={{width:DEVICE_WIDTH,justifyContent:CoverLayer.popupMode.bottom == this.state.displayMode  ? 'flex-end' : 'center',
                                       alignItems:'center',backgroundColor:this.props.coverLayerColor ? this.props.coverLayerColor : 'rgba(0,0,0,0.4)',
                                       position:'absolute',top:0,bottom:0,opacity: this.state.opacityValue}}>
                    <TouchableOpacity style={{width:DEVICE_WIDTH,justifyContent:'center',alignItems:'center',position:'absolute',top:0,bottom:0}}
                                      activeOpacity={1}
                                      onPress={()=>{this.state.coverLayerEvent && this.state.coverLayerEvent()}}/>
                    <Animated.View style={CoverLayer.popupMode.bottom == this.state.displayMode ? {bottom:this.state.bottom} : {transform: [{scale:this.state.scaleValue}]}}>
                        {this.state.renderContent && this.state.renderContent()}
                    </Animated.View>
                </Animated.View>
            );
        }
    }
    
    

    相关文章

      网友评论

          本文标题:react native实现model效果/底部弹出框/中间弹框

          本文链接:https://www.haomeiwen.com/subject/zzecoctx.html