React Native弹窗rnPop组件、仿微信|ios|android弹窗效果



  • rnPop是一个基于React/React-Native技术高自定义Modal模态框,功能效果有些类似android、ios、微信弹窗效果。结合了原生Modal及react能力,使得弹窗高度自定义化,代码结构优雅、简洁、方便

    最近一直在捣鼓react-native技术,上手真心有些困难,踩了不少坑。就想着用react-native技术做个自定义Dialog弹窗来实战下,继续巩固下知识。

    0_1565113052013_Screenshot_1564765821.png

    项目结构

    0_1565113086744_360截图20190806093013820.png

    弹窗调用方式

    • 列表方法一:
      这种调用方式是可以访问组件内部方法,如show、hide方法,可总感觉代码不够优雅,而且不能全局调用
    // 引入rnPop.js组件
    import RNPop from '../utils/rnPop/rnPop.js'
    
    render() {
        return (
            <View style={styles.container}>
                ...
    
                {/* 引入弹窗模板 */}
                <RNPop ref="rnPop" />
            </View>
        )
    }
    
    显示:this.refs.rnPop.show({...options});
    隐藏:this.refs.rnPop.hide();
    
    • 列表方法二:
      通过react-native全局变量global,对外提供全局调用接口rnPop
      这样就可以非常优雅的使用rnPop({...options}) 、 rnPop.close()方式进行弹窗调用
    /**************************
     *    显示弹窗事件(处理传参)
     */
    static show = (args) => {
    	_this.setState({
    		..._this.props, ...args, isVisible: true
    	}, _this.in)
    }
    
    /**************************
     *    关闭弹窗事件
     */
    static close = () => {
    	_this.out()
    }
    
    /**************************
     *    实例化弹窗接口
     */
    const Popup = (args) => {
        RNPop.show(args)
    }
    Popup.close = () => {
        RNPop.close()
    }
    global.rnPop = Popup
    

    0_1565113354252_Screenshot_1564765470.png

    0_1565113358487_Screenshot_1564765487.png

    0_1565113363723_Screenshot_1564765524.png

    //msg提示
        handlePress01 = ()=> {
            rnPop({
                content: 'msg消息提示框(5s后窗口关闭)',
                shade: true,
                shadeClose: false,
                time: 5,
                xtime: true,
                anim: 'fadeIn',
            });
        }
    
        //msg提示(黑色背景)
        handlePress02 = ()=> {
            rnPop({
                content: '自定义弹窗背景',
                shade: false,
                style: {backgroundColor: 'rgba(17,17,17,.7)', borderRadius: 6},
                contentStyle: {color: '#fff', padding: 10},
                time: 2
            });
        }
    

    0_1565113403869_Screenshot_1564765638.png

    0_1565113411608_Screenshot_1564765672.png

    react-native自定义toast支持四种图标 success/info/error/loading

    //Toast演示
    handlePress15 = ()=> {
    	rnPop({
    		skin: 'toast',
    		content: '操作成功',
    		icon: 'success', //success | info | error | loading
    		shade: false,
    		time: 3
    	});
    }
    

    0_1565113456333_Screenshot_1564765559.png

    0_1565113461768_Screenshot_1564765566.png

    0_1565113468224_Screenshot_1564765776.png

    0_1565113473095_Screenshot_1564765784.png

    0_1565113477540_Screenshot_1564765802.png

    0_1565113481557_Screenshot_1564765821.png

    0_1565113488093_Screenshot_1564765829.png

    0_1565113493459_Screenshot_1564765851.png

    emmm,是不是感觉还OK,不过总感觉少了点什么, 没错, 还差个自定义弹窗模板
    还支持对传入content参数进行自定义模板 content: string | object

    // 自定义调用
    handlePressAA = () => {
    	rnPop({
    		content: (
    			<DefineCp />
    
    			// <View style={{alignItems: 'center', justifyContent: 'center'}}>
    			//     <Image style={{height: 200, width: 200}} source={require('../assets/qrcode.jpg')} />
    			//     <Text style={{color: '#999'}}>长按或扫一扫二维码,加我好友</Text>
    			//     <View><Text onPress={rnPop.close} style={{backgroundColor: '#61dafb', borderRadius: 20, color: '#fff', marginTop: 15, marginBottom: 10, paddingVertical: 5, paddingHorizontal: 50}}>保存二维码</Text></View>
    			// </View>
    		),
    		anim: 'bottom'
    	});
    }
    
    
    // 自定义模板
    const DefineCp = () => {
        return (
            <View style={{alignItems: 'center', justifyContent: 'center'}}>
                <Image style={{height: 200, width: 200}} source={require('../assets/qrcode.jpg')} />
                <Text style={{color: '#999'}}>长按或扫一扫二维码,加我好友</Text>
                <View><Text onPress={rnPop.close} style={{backgroundColor: '#61dafb', borderRadius: 20, color: '#fff', marginTop: 15, marginBottom: 10, paddingVertical: 5, paddingHorizontal: 50}}>保存二维码</Text></View>
            </View>
        )
    }
    

    0_1565113607366_Screenshot_1565056841.png

    /**
     * @Title         react-native弹窗插件 rnPop-v1.0 beta (UTF-8)
     * @Create        2019/08/01 10:00:50 GMT+0800 (中国标准时间)
     * @Author        andy 
     */
    
    'use strict'
    
    import React, {Component} from 'react'
    import {
        Animated, Easing, StyleSheet, Dimensions, PixelRatio, TouchableHighlight, Modal, View, Text, Image, ActivityIndicator
    } from 'react-native'
    
    const pixel = PixelRatio.get()
    const {width, height} = Dimensions.get('window')
    
    export default class RNPop extends Component{
        /**************************
         *    弹窗配置参数
         */
        static defaultProps = {
            isVisible: false,       //弹窗显示
    
            title: '',              //标题
            content: '',            //内容
            style: null,            //自定义弹窗样式 {object}
            contentStyle: null,     //内容样式
            skin: '',               //自定义弹窗风格
            icon: '',               //自定义弹窗图标
    
            shade: true,            //遮罩层
            shadeClose: true,       //点击遮罩层关闭
            opacity: '',            //遮罩层透明度
            time: 0,                //弹窗自动关闭秒数
            xtime: false,           //显示关闭秒数
    
            anim: 'scaleIn',        //弹窗动画(scaleIn / fadeIn / top / bottom / left / right)
            follow: null,            //跟随定位(适用于在长按位置定位弹窗)
            position: '',           //弹窗位置
    
            btns: null,             //弹窗按钮(不设置则不显示按钮)[{...options}, {...options}]
        }
    
        constructor(props){
            super(props)
    
            this.state = {
                ...this.props,
                animatedValue: new Animated.Value(0),
            }
            this.timer = null
        }
    
        render(){
            let opt = this.state
    
            // __自定义toast图标
            let slotImg = {
                success: require('./skin/success.png'),
                error: require('./skin/error.png'),
                info: require('./skin/info.png'),
            }
    
            return (
                ...
            )
            
        }
    
        // 执行动画
        in = () => {
            Animated.timing(
                this.state.animatedValue, {easing: Easing.linear, duration: 300, toValue: 1}
            ).start()
        }
        out = () => {
            Animated.timing(
                this.state.animatedValue, {easing: Easing.linear, duration: 100, toValue: 0}
            ).start(()=>{
                this.setState({
                    ...this.props
                })
            })
    
            this.timer && clearTimeout(this.timer)
            delete this.timer
        }
    
        /**************************
         *    显示弹窗事件(处理传参)
         */
        static show = (args) => {
            _this.setState({
                ..._this.props, ...args, isVisible: true
            }, _this.in)
        }
    
        /**************************
         *    关闭弹窗事件
         */
        static close = () => {
            _this.out()
        }
    }
    


  • 没demo吗 老哥