[RN] 实现底部弹出框/中间弹框

https://www.jianshu.com/p/14087afc21ed

CoverLayer.js:

import React, { useImperativeHandle, useRef, useState } from 'react';
import {
    TouchableOpacity,
    View,
    Animated,
} from 'react-native';
import Constants from '../Contants';

const c_duration = 200;
const c_deviceHeight = Constants.Dimension.ScreenHeight();

export const popupMode = {
    center: "center",
    bottom: "bottom"
};
const CoverLayer = (props, ref) => {
    const opacityValue = useRef(new Animated.Value(0)).current;
    const scaleValue = useRef(new Animated.Value(1.1)).current;
    const bottom = useRef(new Animated.Value(-c_deviceHeight)).current;
    const [isShow, setIsShow] = useState(false);
    const [displayMode, setDisplayMode] = useState(null);
    // const [renderContent, setRenderContent] = useState(props.renderContent);
    // const [coverLayerEvent, setCoverLayerEvent] = useState(props.coverLayerEvent);
    const renderContent = useRef(null);
    renderContent.current = props.renderContent;
    const coverLayerEvent = useRef(null);
    coverLayerEvent.current = props.coverLayerEvent;
    // const { renderContent, coverLayerEvent } = props;
    useImperativeHandle(ref, () => ({
        showWithContent: (renderContent, coverLayerEvent, displayMode) => {
            showWithContent(renderContent, coverLayerEvent, displayMode);
        },
        show: (displayMode) => {
            show(displayMode);
        },
        hide: (callback) => {
            hide(callback);
        }
    }));

    /**
     * 显示弹框(该方法是为了简化一个界面有多个弹框的情况)
     * renderContent: func, 渲染弹框内容的方法, 会覆盖props.renderContent
     * coverLayerEvent: func, 点击背景触发的事件, 会覆盖props.coverLayerEvent
     **/
    const showWithContent = async (renderContent, coverLayerEvent, displayMode) => {
        if (isShow) {
            hide(displayMode, async () => {
                await function () {
                    // setCoverLayerEvent(coverLayerEvent)
                    // setRenderContent(renderContent)
                    coverLayerEvent.current = coverLayerEvent
                    renderContent.current = renderContent
                };
                show(displayMode);
            })
        } else {
            await function () {
                // setCoverLayerEvent(coverLayerEvent)
                // setRenderContent(renderContent)
                coverLayerEvent.current = coverLayerEvent
                renderContent.current = renderContent
            };
            show(displayMode);
        }
    }

    // 显示弹框
    const show = (displayMode) => {
        setIsShow(true);
        setDisplayMode(displayMode)
        try {
            Animated.parallel([
                Animated.timing(opacityValue, {
                    toValue: 1,
                    duration: c_duration,
                    useNativeDriver: true,
                }),
                popupMode.bottom == displayMode ? showFromBottom() : showFromCenter()
            ]).start();
        } catch (error) {
            console.log(error)
        }

    }

    // 从中间弹出界面
    const showFromCenter = () => {
        return (
            Animated.timing(scaleValue, {
                toValue: 1,
                duration: c_duration,
                useNativeDriver: true,
            })
        )
    }

    // 从底部弹出界面
    const showFromBottom = () => {
        return (
            Animated.timing(bottom, {
                toValue: 0,
                duration: c_duration,
                useNativeDriver: true,
            })
        )
    }

    // 隐藏弹框
    const hide = (callback) => {
        Animated.parallel([
            Animated.timing(opacityValue, {
                toValue: 0,
                duration: c_duration,
                useNativeDriver: true,
            }),
            popupMode.bottom == displayMode ? hideFromBottom() : hideFromCenter()
        ]).start(async () => {
            await setIsShow(false);
            callback && callback();
        });
    }

    //从中间隐藏
    const hideFromCenter = () => {
        return (
            Animated.timing(scaleValue, {
                toValue: 1.1,
                duration: c_duration,
                useNativeDriver: true,
            })
        )
    }

    // 从底部隐藏
    const hideFromBottom = () => {
        return (
            Animated.timing(bottom, {
                toValue: -c_deviceHeight,
                duration: c_duration,
                useNativeDriver: true,
            })
        )
    }

    return (
        isShow &&
        <Animated.View style={{
            width: Constants.Dimension.ScreenWidth(),
            justifyContent: popupMode.bottom == displayMode ? 'flex-end' : 'center',
            alignItems: 'center',
            backgroundColor: props.coverLayerColor ? props.coverLayerColor : 'rgba(0,0,0,0.4)',
            position: 'absolute',
            top: 0,
            bottom: 0,
            opacity: opacityValue
        }}>
            <TouchableOpacity style={{
                width: Constants.Dimension.ScreenWidth(),
                justifyContent: 'center',
                alignItems: 'center',
                position: 'absolute',
                bottom: 0,
                top: 0,
            }}
                activeOpacity={1}
                onPress={() => { coverLayerEvent.current && coverLayerEvent.current() }} />
            <Animated.View style={popupMode.bottom == displayMode ?
                { translateY: bottom } : { transform: [{ scale: scaleValue }] }}>
                {renderContent.current && renderContent.current()}
            </Animated.View>
        </Animated.View>
    );
}

export default React.forwardRef(CoverLayer);

调用:

<CoverLayer
                ref={ref => coverLayer.current = ref}
                renderContent={() => {
                    return (
                        <View style={{width:100,height:100,background:'red'}}/>
                    )
                }}
                coverLayerEvent={() => {
                    console.log('点击背景')
                    coverLayer.current && coverLayer.current.hide && coverLayer.current.hide()
                }}
                coverLayerColor="rgba(0,0,0,0.2)"
            />


coverLayer.current.show(popupMode.bottom)

// or
coverLayer.current.showWithContent(renderBottomLayout, () => {
                        coverLayer.current && coverLayer.current.hide && coverLayer.current.hide()
                    }, popupMode.bottom)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值