React Native自定义底部弹框

295 阅读2分钟

弹窗组件允许开发者创建一个可以覆盖屏幕内容的视图,通常用于显示表单、菜单或其他需要用户交互的组件。在原生开发中可以使用ActionSheet来实现底部弹框,在React Native开发中,官方虽然提供了Modal组件来实现弹框效果,但是Modal组件使用起来并不方便,所以推荐大家使用react-native-modal。

react-native-modal是一个增强的,动画的和可定制的react-native模态对话框开源组件,它提供的API比较丰富,基本可以满足开发中需要的各种对话弹框,它附带遮罩层以模态的形式弹出。具有如下一些特点:

  • 增强型和可定制:react-native-modal 提供了比React Native 核心组件 Modal 更丰富的功能和定制选项。
  • 动画支持:它内置了流畅的进入和退出动画效果,使模态框的显示和隐藏更加自然。
  • 灵活的API:开发者可以轻松地配置模态框的各种属性,如背景的不透明度、颜色、动画类型等。
  • 易于集成:该组件易于集成到React Native 项目中,并且提供了简单的API,方便开发者使用。
  • 模态形式的弹出:react-native-modal 以模态形式弹出,可以用于展示重要信息、提示用户操作或收集用户输入。

在RN项目中使用react-native-modal需要先安装插件:

npm install react-native-modal --save

然后就可以使用react-native-modal提供的Modal组件来实现各种弹框效果了,以下是使用Modal组件实现底部弹框的示例代码:

import { StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
import Modal from 'react-native-modal';

export type Option = {
    label: string;
    value: string;
};

export type ActionSheetProps = {
    visible: boolean;
    title: string;
    options: Option[];
    onSelect: (option: Option) => void;
    onClose: () => void;
};

const ActionSheet: React.FC<ActionSheetProps> = ({
    visible,
    title,
    options,
    onSelect,
    onClose,
}) => {

    return (
        <Modal
            swipeDirection="down"
            isVisible={visible}
            style={styles.modal}
        >

            <TouchableWithoutFeedback
                style={styles.overlay}
                onPress={onClose}
            >
                <View style={styles.actionSheetContainer}>
                    <Text style={styles.actionSheetTitle}>{title}</Text>

                    {options.map((option, index) => (
                        <TouchableOpacity
                            key={index}
                            style={[
                                styles.actionSheetItem,
                                index === options.length - 1 && styles.lastItem,
                            ]}
                            onPress={() => {
                                onSelect(option);
                                onClose();
                            }}
                        >
                            <Text style={styles.actionSheetText}>{option.label}</Text>
                        </TouchableOpacity>
                    ))}
                </View>
            </TouchableWithoutFeedback>
        </Modal>
    );
};

const styles = StyleSheet.create({
    modal: {
        justifyContent: 'flex-end',
        margin: 0,
    },
    overlay: {
        flex: 1,
        backgroundColor: 'rgba(0,0,0,0.4)',
        justifyContent: 'flex-end',
    },
    actionSheetContainer: {
        backgroundColor: '#fff',
        borderTopLeftRadius: 16,
        borderTopRightRadius: 16,
    },
    actionSheetTitle: {
        fontSize: 16,
        paddingVertical: 20,
        fontWeight: "600",
        fontFamily: "PingFang SC",
        textAlign: "center",
        textAlignVertical: 'center',
    },
    actionSheetItem: {
        paddingVertical: 20,
        borderBottomWidth: 1,
        alignItems: 'center',
    },
    actionSheetText: {
        fontSize: 14,
    },
    lastItem: {
        borderBottomWidth: 0,
        marginTop: 8,
        backgroundColor: '#F7F7F7',
    },
});

export default ActionSheet;

然后在业务代码中使用上面的自定义ActionSheet组件,如下所示:

 const [actionSheetVisible, setActionSheetVisible] = useState(false);

const handleOptionSelect = (option: Option) => {
    console.log(option.label)
    // if (option.value !== 'cancel') {
    //     setActionSheetVisible(false);
    // }
  };

function renderActionSheet() {
    const options: Option[] = [
      { label: '取消', value: 'cancel' },
    ];
    return (<ActionSheet
      visible={actionSheetVisible}
      title="查看开通记录"
      options={options}
      onSelect={handleOptionSelect}
      onClose={() => setActionSheetVisible(false)}
    />
    )
  }

最终的运行效果如下图:

1750474393035.jpg