React Native【实战范例】 内置组件 modal 的使用(含对话框,底部弹出选择器)

发布于:2025-06-19 ⋅ 阅读:(15) ⋅ 点赞:(0)

对话框

在这里插入图片描述

import React, { useState } from "react";
import {
  Button,
  Modal,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from "react-native";
// 定义 ConfirmDialog 的 props 类型
interface ConfirmDialogProps {
  visible: boolean;
  onConfirm: () => void;
  onCancel: () => void;
  title: string;
  message: string;
}
const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
  visible,
  onConfirm,
  onCancel,
  title,
  message,
}) => {
  return (
    <Modal
      animationType="fade"
      transparent={true}
      visible={visible}
      onRequestClose={onCancel}
    >
      <View style={styles.modalOverlay}>
        <View style={styles.confirmDialog}>
          <Text style={styles.dialogTitle}>{title}</Text>
          <Text style={styles.dialogMessage}>{message}</Text>
          <View style={styles.buttonContainer}>
            <TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
              <Text style={styles.cancelButtonText}>取消</Text>
            </TouchableOpacity>
            <TouchableOpacity style={styles.confirmButton} onPress={onConfirm}>
              <Text style={styles.confirmButtonText}>确认</Text>
            </TouchableOpacity>
          </View>
        </View>
      </View>
    </Modal>
  );
};
const App: React.FC = () => {
  const [isConfirmVisible, setConfirmVisible] = useState(false);
  const handleDelete = () => {
    // 模拟删除操作
    console.log("执行删除操作...");
    setConfirmVisible(false);
  };
  return (
    <View style={styles.container}>
      <Button
        title="删除数据"
        color="red"
        onPress={() => setConfirmVisible(true)}
      />
      <ConfirmDialog
        visible={isConfirmVisible}
        title="确认删除"
        message="确定要删除这条数据吗?此操作不可撤销。"
        onConfirm={handleDelete}
        onCancel={() => setConfirmVisible(false)}
      />
    </View>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    padding: 16,
  },
  modalOverlay: {
    flex: 1,
    backgroundColor: "rgba(0,0,0,0.5)",
    justifyContent: "center",
    padding: 16,
  },
  confirmDialog: {
    backgroundColor: "white",
    borderRadius: 8,
    padding: 20,
  },
  dialogTitle: {
    fontSize: 18,
    fontWeight: "bold",
    marginBottom: 10,
  },
  dialogMessage: {
    fontSize: 16,
    marginBottom: 20,
  },
  buttonContainer: {
    flexDirection: "row",
    justifyContent: "flex-end",
  },
  cancelButton: {
    padding: 10,
    marginRight: 10,
  },
  cancelButtonText: { color: "gray" },
  confirmButton: {
    padding: 10,
    backgroundColor: "red",
    borderRadius: 5,
  },
  confirmButtonText: {
    color: "white",
  },
});
export default App;

底部弹出选择器

在这里插入图片描述

import React, { useState } from 'react';
import { View, Text, Modal, StyleSheet, TouchableOpacity, SafeAreaView } from 'react-native';

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

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

const ActionSheet: React.FC<ActionSheetProps> = ({
  visible,
  options,
  onSelect,
  onClose,
}) => {
  return (
    <Modal
      animationType="slide"
      transparent={true}
      visible={visible}
      onRequestClose={onClose}
    >
      <TouchableOpacity 
        style={styles.overlay} 
        activeOpacity={1} 
        onPress={onClose}
      >
        <View style={styles.actionSheetContainer}>
          {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>
      </TouchableOpacity>
    </Modal>
  );
};

const App: React.FC = () => {
  const [isActionSheetVisible, setActionSheetVisible] = useState(false);
  const [selectedOption, setSelectedOption] = useState<Option | null>(null);

  const options: Option[] = [
    { label: '拍照', value: 'camera' },
    { label: '从相册选择', value: 'gallery' },
    { label: '取消', value: 'cancel' },
  ];

  const handleOptionSelect = (option: Option) => {
    if (option.value !== 'cancel') {
      setSelectedOption(option);
    }
  };

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.content}>
        <Text style={styles.selectedText}>
          {selectedOption ? `已选择: ${selectedOption.label}` : '请选择操作'}
        </Text>
        <TouchableOpacity 
          style={styles.button} 
          onPress={() => setActionSheetVisible(true)}
        >
          <Text style={styles.buttonText}>选择图片</Text>
        </TouchableOpacity>
      </View>
      
      <ActionSheet
        visible={isActionSheetVisible}
        options={options}
        onSelect={handleOptionSelect}
        onClose={() => setActionSheetVisible(false)}
      />
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  content: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 16,
  },
  selectedText: {
    fontSize: 18,
    marginBottom: 20,
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 12,
    borderRadius: 8,
    width: '100%',
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
  },
  overlay: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.4)',
    justifyContent: 'flex-end',
  },
  actionSheetContainer: {
    backgroundColor: 'white',
    borderTopLeftRadius: 16,
    borderTopRightRadius: 16,
  },
  actionSheetItem: {
    padding: 20,
    borderBottomWidth: 1,
    borderBottomColor: '#EEEEEE',
    alignItems: 'center',
  },
  lastItem: {
    borderBottomWidth: 0,
    marginTop: 8,
    backgroundColor: '#F7F7F7',
  },
  actionSheetText: {
    fontSize: 18,
  },
});

export default App;

网站公告

今日签到

点亮在社区的每一天
去签到